Merge branch 'kvm-updates/2.6.36' of git://git.kernel.org/pub/scm/virt/kvm/kvm
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 4 Aug 2010 17:43:01 +0000 (10:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 4 Aug 2010 17:43:01 +0000 (10:43 -0700)
* 'kvm-updates/2.6.36' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (198 commits)
  KVM: VMX: Fix host GDT.LIMIT corruption
  KVM: MMU: using __xchg_spte more smarter
  KVM: MMU: cleanup spte set and accssed/dirty tracking
  KVM: MMU: don't atomicly set spte if it's not present
  KVM: MMU: fix page dirty tracking lost while sync page
  KVM: MMU: fix broken page accessed tracking with ept enabled
  KVM: MMU: add missing reserved bits check in speculative path
  KVM: MMU: fix mmu notifier invalidate handler for huge spte
  KVM: x86 emulator: fix xchg instruction emulation
  KVM: x86: Call mask notifiers from pic
  KVM: x86: never re-execute instruction with enabled tdp
  KVM: Document KVM_GET_SUPPORTED_CPUID2 ioctl
  KVM: x86: emulator: inc/dec can have lock prefix
  KVM: MMU: Eliminate redundant temporaries in FNAME(fetch)
  KVM: MMU: Validate all gptes during fetch, not just those used for new pages
  KVM: MMU: Simplify spte fetch() function
  KVM: MMU: Add gpte_valid() helper
  KVM: MMU: Add validate_direct_spte() helper
  KVM: MMU: Add drop_large_spte() helper
  KVM: MMU: Use __set_spte to link shadow pages
  ...

1151 files changed:
Documentation/DocBook/dvb/dvbapi.xml
Documentation/DocBook/dvb/frontend.h.xml
Documentation/DocBook/dvb/frontend.xml
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/media.tmpl
Documentation/DocBook/v4l/lirc_device_interface.xml [new file with mode: 0644]
Documentation/DocBook/v4l/remote_controllers.xml
Documentation/apparmor.txt [new file with mode: 0644]
Documentation/arm/memory.txt
Documentation/arm/tcm.txt
Documentation/credentials.txt
Documentation/dvb/get_dvb_firmware
Documentation/feature-removal-schedule.txt
Documentation/filesystems/xfs.txt
Documentation/input/multi-touch-protocol.txt
Documentation/kernel-parameters.txt
Documentation/tomoyo.txt
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/gspca.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/Makefile.debug [deleted file]
arch/arm/boot/compressed/head-l7200.S [deleted file]
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/misc.c
arch/arm/common/gic.c
arch/arm/common/sa1111.c
arch/arm/configs/kirkwood_defconfig
arch/arm/configs/lusl7200_defconfig [deleted file]
arch/arm/include/asm/elf.h
arch/arm/include/asm/hwcap.h
arch/arm/include/asm/io.h
arch/arm/include/asm/irq.h
arch/arm/include/asm/kexec.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/mach/irq.h
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/mach/pci.h
arch/arm/include/asm/memblock.h [new file with mode: 0644]
arch/arm/include/asm/memory.h
arch/arm/include/asm/mmzone.h [deleted file]
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/setup.h
arch/arm/include/asm/stackprotector.h [new file with mode: 0644]
arch/arm/include/asm/system.h
arch/arm/include/asm/tls.h [new file with mode: 0644]
arch/arm/include/asm/vfpmacros.h
arch/arm/kernel/Makefile
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/compat.c
arch/arm/kernel/compat.h
arch/arm/kernel/crash_dump.c [new file with mode: 0644]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/irq.c
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/relocate_kernel.S
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kernel/smp_twd.c
arch/arm/kernel/tcm.c
arch/arm/kernel/traps.c
arch/arm/lib/Makefile
arch/arm/lib/csumpartialcopyuser.S
arch/arm/mach-aaec2000/include/mach/memory.h
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-snapper9260.c [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
arch/arm/mach-at91/include/mach/at91sam9260.h
arch/arm/mach-at91/include/mach/at91sam9261.h
arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
arch/arm/mach-at91/include/mach/at91sam9rl.h
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/gpio.h
arch/arm/mach-at91/pm.h
arch/arm/mach-at91/pm_slowclock.S
arch/arm/mach-bcmring/core.c
arch/arm/mach-clps711x/Kconfig
arch/arm/mach-clps711x/clep7312.c
arch/arm/mach-clps711x/edb7211-arch.c
arch/arm/mach-clps711x/fortunet.c
arch/arm/mach-clps711x/include/mach/memory.h
arch/arm/mach-cns3xxx/Makefile
arch/arm/mach-cns3xxx/cns3420vb.c
arch/arm/mach-cns3xxx/devices.c [new file with mode: 0644]
arch/arm/mach-cns3xxx/devices.h [new file with mode: 0644]
arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
arch/arm/mach-cns3xxx/pcie.c [new file with mode: 0644]
arch/arm/mach-cns3xxx/pm.c
arch/arm/mach-davinci/include/mach/memory.h
arch/arm/mach-dove/common.c
arch/arm/mach-dove/common.h
arch/arm/mach-dove/dove-db-setup.c
arch/arm/mach-ep93xx/adssphere.c
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-ep93xx/micro9.c
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-imx/Kconfig [moved from arch/arm/mach-mx2/Kconfig with 57% similarity]
arch/arm/mach-imx/Makefile [moved from arch/arm/mach-mx2/Makefile with 55% similarity]
arch/arm/mach-imx/Makefile.boot [moved from arch/arm/mach-mx2/Makefile.boot with 67% similarity]
arch/arm/mach-imx/clock-imx1.c [moved from arch/arm/mach-mx1/clock.c with 90% similarity]
arch/arm/mach-imx/clock-imx21.c [moved from arch/arm/mach-mx2/clock_imx21.c with 100% similarity]
arch/arm/mach-imx/clock-imx27.c [moved from arch/arm/mach-mx2/clock_imx27.c with 99% similarity]
arch/arm/mach-imx/cpu-imx27.c [moved from arch/arm/mach-mx2/cpu_imx27.c with 100% similarity]
arch/arm/mach-imx/devices-imx1.h [new file with mode: 0644]
arch/arm/mach-imx/devices-imx21.h [new file with mode: 0644]
arch/arm/mach-imx/devices-imx27.h [new file with mode: 0644]
arch/arm/mach-imx/devices.c [moved from arch/arm/mach-mx2/devices.c with 67% similarity]
arch/arm/mach-imx/devices.h [moved from arch/arm/mach-mx2/devices.h with 54% similarity]
arch/arm/mach-imx/dma-v1.c [moved from arch/arm/plat-mxc/dma-mx1-mx2.c with 99% similarity]
arch/arm/mach-imx/eukrea_mbimx27-baseboard.c [moved from arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c with 52% similarity]
arch/arm/mach-imx/include/mach/dma-mx1-mx2.h [new file with mode: 0644]
arch/arm/mach-imx/include/mach/dma-v1.h [moved from arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h with 93% similarity]
arch/arm/mach-imx/mach-cpuimx27.c [moved from arch/arm/mach-mx2/mach-cpuimx27.c with 66% similarity]
arch/arm/mach-imx/mach-imx27lite.c [moved from arch/arm/mach-mx2/mach-imx27lite.c with 86% similarity]
arch/arm/mach-imx/mach-mx1ads.c [moved from arch/arm/mach-mx1/mach-mx1ads.c with 81% similarity]
arch/arm/mach-imx/mach-mx21ads.c [moved from arch/arm/mach-mx2/mach-mx21ads.c with 77% similarity]
arch/arm/mach-imx/mach-mx27_3ds.c [moved from arch/arm/mach-mx2/mach-mx27_3ds.c with 74% similarity]
arch/arm/mach-imx/mach-mx27ads.c [moved from arch/arm/mach-mx2/mach-mx27ads.c with 82% similarity]
arch/arm/mach-imx/mach-mxt_td60.c [moved from arch/arm/mach-mx2/mach-mxt_td60.c with 86% similarity]
arch/arm/mach-imx/mach-pca100.c [moved from arch/arm/mach-mx2/mach-pca100.c with 80% similarity]
arch/arm/mach-imx/mach-pcm038.c [moved from arch/arm/mach-mx2/mach-pcm038.c with 91% similarity]
arch/arm/mach-imx/mach-scb9328.c [moved from arch/arm/mach-mx1/mach-scb9328.c with 89% similarity]
arch/arm/mach-imx/mm-imx1.c [moved from arch/arm/mach-mx1/generic.c with 68% similarity]
arch/arm/mach-imx/mm-imx21.c [moved from arch/arm/mach-mx2/mm-imx21.c with 95% similarity]
arch/arm/mach-imx/mm-imx27.c [moved from arch/arm/mach-mx2/mm-imx27.c with 95% similarity]
arch/arm/mach-imx/mx1-camera-fiq-ksym.c [moved from arch/arm/mach-mx1/ksym_mx1.c with 100% similarity]
arch/arm/mach-imx/mx1-camera-fiq.S [moved from arch/arm/mach-mx1/mx1_camera_fiq.S with 100% similarity]
arch/arm/mach-imx/pcm970-baseboard.c [moved from arch/arm/mach-mx2/pcm970-baseboard.c with 100% similarity]
arch/arm/mach-imx/pm-imx27.c [new file with mode: 0644]
arch/arm/mach-integrator/common.h [new file with mode: 0644]
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-integrator/pci_v3.c
arch/arm/mach-iop13xx/include/mach/memory.h
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-ixp2000/pci.c
arch/arm/mach-ixp23xx/pci.c
arch/arm/mach-ixp4xx/common-pci.c
arch/arm/mach-ixp4xx/include/mach/memory.h
arch/arm/mach-kirkwood/Kconfig
arch/arm/mach-kirkwood/Makefile
arch/arm/mach-kirkwood/addr-map.c
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/common.h
arch/arm/mach-kirkwood/db88f6281-bp-setup.c
arch/arm/mach-kirkwood/include/mach/bridge-regs.h
arch/arm/mach-kirkwood/include/mach/irqs.h
arch/arm/mach-kirkwood/include/mach/kirkwood.h
arch/arm/mach-kirkwood/include/mach/leds-ns2.h [new file with mode: 0644]
arch/arm/mach-kirkwood/mpp.c
arch/arm/mach-kirkwood/mpp.h
arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
arch/arm/mach-kirkwood/netspace_v2-setup.c
arch/arm/mach-kirkwood/netxbig_v2-setup.c
arch/arm/mach-kirkwood/openrd-setup.c
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
arch/arm/mach-kirkwood/rd88f6281-setup.c
arch/arm/mach-kirkwood/t5325-setup.c [new file with mode: 0644]
arch/arm/mach-kirkwood/ts219-setup.c
arch/arm/mach-kirkwood/ts41x-setup.c
arch/arm/mach-ks8695/pci.c
arch/arm/mach-l7200/Makefile [deleted file]
arch/arm/mach-l7200/Makefile.boot [deleted file]
arch/arm/mach-l7200/core.c [deleted file]
arch/arm/mach-l7200/include/mach/aux_reg.h [deleted file]
arch/arm/mach-l7200/include/mach/debug-macro.S [deleted file]
arch/arm/mach-l7200/include/mach/entry-macro.S [deleted file]
arch/arm/mach-l7200/include/mach/gp_timers.h [deleted file]
arch/arm/mach-l7200/include/mach/gpio.h [deleted file]
arch/arm/mach-l7200/include/mach/hardware.h [deleted file]
arch/arm/mach-l7200/include/mach/io.h [deleted file]
arch/arm/mach-l7200/include/mach/irqs.h [deleted file]
arch/arm/mach-l7200/include/mach/memory.h [deleted file]
arch/arm/mach-l7200/include/mach/pmpcon.h [deleted file]
arch/arm/mach-l7200/include/mach/pmu.h [deleted file]
arch/arm/mach-l7200/include/mach/serial.h [deleted file]
arch/arm/mach-l7200/include/mach/serial_l7200.h [deleted file]
arch/arm/mach-l7200/include/mach/sib.h [deleted file]
arch/arm/mach-l7200/include/mach/sys-clock.h [deleted file]
arch/arm/mach-l7200/include/mach/system.h [deleted file]
arch/arm/mach-l7200/include/mach/time.h [deleted file]
arch/arm/mach-l7200/include/mach/timex.h [deleted file]
arch/arm/mach-l7200/include/mach/uncompress.h [deleted file]
arch/arm/mach-l7200/include/mach/vmalloc.h [deleted file]
arch/arm/mach-lh7a40x/include/mach/memory.h
arch/arm/mach-lpc32xx/Kconfig [new file with mode: 0644]
arch/arm/mach-lpc32xx/Makefile [new file with mode: 0644]
arch/arm/mach-lpc32xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-lpc32xx/clock.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/clock.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/common.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/common.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/gpiolib.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/clkdev.h [moved from arch/arm/plat-mxc/include/mach/board-pcm043.h with 57% similarity]
arch/arm/mach-lpc32xx/include/mach/debug-macro.S [moved from arch/arm/plat-mxc/include/mach/board-mx35pdk.h with 55% similarity]
arch/arm/mach-lpc32xx/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/i2c.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/io.h [moved from arch/arm/plat-mxc/include/mach/board-pcm037.h with 57% similarity]
arch/arm/mach-lpc32xx/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/platform.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/irq.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/phy3250.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/pm.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/serial.c [new file with mode: 0644]
arch/arm/mach-lpc32xx/suspend.S [new file with mode: 0644]
arch/arm/mach-lpc32xx/timer.c [new file with mode: 0644]
arch/arm/mach-msm/Makefile
arch/arm/mach-msm/board-trout-gpio.c [new file with mode: 0644]
arch/arm/mach-msm/board-trout.c
arch/arm/mach-msm/board-trout.h
arch/arm/mach-msm/include/mach/gpio.h
arch/arm/mach-mx1/Kconfig [deleted file]
arch/arm/mach-mx1/Makefile [deleted file]
arch/arm/mach-mx1/Makefile.boot [deleted file]
arch/arm/mach-mx1/crm_regs.h [deleted file]
arch/arm/mach-mx1/devices.c [deleted file]
arch/arm/mach-mx1/devices.h [deleted file]
arch/arm/mach-mx2/serial.c [deleted file]
arch/arm/mach-mx25/Kconfig
arch/arm/mach-mx25/Makefile
arch/arm/mach-mx25/clock.c
arch/arm/mach-mx25/devices-imx25.h [new file with mode: 0644]
arch/arm/mach-mx25/devices.c
arch/arm/mach-mx25/devices.h
arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c [new file with mode: 0644]
arch/arm/mach-mx25/mach-cpuimx25.c [new file with mode: 0644]
arch/arm/mach-mx25/mach-mx25_3ds.c [moved from arch/arm/mach-mx25/mach-mx25pdk.c with 76% similarity]
arch/arm/mach-mx25/mm.c
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/clock-imx35.c
arch/arm/mach-mx3/devices-imx31.h [new file with mode: 0644]
arch/arm/mach-mx3/devices-imx35.h [new file with mode: 0644]
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/devices.h
arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c [new file with mode: 0644]
arch/arm/mach-mx3/mach-armadillo5x0.c
arch/arm/mach-mx3/mach-cpuimx35.c [new file with mode: 0644]
arch/arm/mach-mx3/mach-kzm_arm11_01.c
arch/arm/mach-mx3/mach-mx31_3ds.c
arch/arm/mach-mx3/mach-mx31ads.c
arch/arm/mach-mx3/mach-mx31lilly.c
arch/arm/mach-mx3/mach-mx31lite.c
arch/arm/mach-mx3/mach-mx31moboard.c
arch/arm/mach-mx3/mach-mx35_3ds.c [moved from arch/arm/mach-mx3/mach-mx35pdk.c with 89% similarity]
arch/arm/mach-mx3/mach-pcm037.c
arch/arm/mach-mx3/mach-pcm037_eet.c
arch/arm/mach-mx3/mach-pcm043.c
arch/arm/mach-mx3/mach-qong.c
arch/arm/mach-mx3/mm.c
arch/arm/mach-mx3/mx31lilly-db.c
arch/arm/mach-mx3/mx31lite-db.c
arch/arm/mach-mx3/mx31moboard-devboard.c
arch/arm/mach-mx3/mx31moboard-marxbot.c
arch/arm/mach-mx3/mx31moboard-smartbot.c
arch/arm/mach-mx5/Kconfig
arch/arm/mach-mx5/Makefile
arch/arm/mach-mx5/board-cpuimx51.c [new file with mode: 0644]
arch/arm/mach-mx5/board-mx51_3ds.c [new file with mode: 0644]
arch/arm/mach-mx5/board-mx51_babbage.c
arch/arm/mach-mx5/clock-mx51.c
arch/arm/mach-mx5/devices.c
arch/arm/mach-mx5/devices.h
arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c [new file with mode: 0644]
arch/arm/mach-mx5/mm.c
arch/arm/mach-mxc91231/crm_regs.h
arch/arm/mach-mxc91231/devices.c
arch/arm/mach-mxc91231/mm.c
arch/arm/mach-nomadik/clock.c
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-generic.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-htcherald.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-palmtt.c
arch/arm/mach-omap1/board-palmz71.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/board-sx1.c
arch/arm/mach-omap1/board-voiceblue.c
arch/arm/mach-omap1/io.c
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-3630sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.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-omap3touchbook.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/board-zoom3.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/io.c
arch/arm/mach-orion5x/Kconfig
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/include/mach/system.h
arch/arm/mach-pxa/cm-x2xx-pci.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/eseries.c
arch/arm/mach-pxa/generic.h
arch/arm/mach-pxa/include/mach/memory.h
arch/arm/mach-pxa/palmt5.c
arch/arm/mach-pxa/palmtreo.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/include/mach/board-pb1176.h
arch/arm/mach-realview/include/mach/irqs-pb1176.h
arch/arm/mach-realview/include/mach/memory.h
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/mach-h1940.c
arch/arm/mach-s3c2412/mach-smdk2413.c
arch/arm/mach-s3c2412/mach-vstms.c
arch/arm/mach-s3c2440/mach-rx1950.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/include/mach/memory.h
arch/arm/mach-shark/include/mach/memory.h
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/include/mach/irqs.h
arch/arm/mach-spear3xx/clock.c
arch/arm/mach-spear6xx/clock.c
arch/arm/mach-u300/clock.c
arch/arm/mach-u300/include/mach/memory.h
arch/arm/mach-u300/u300.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/clock.c
arch/arm/mach-ux500/devices-db8500.c
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/irqs-db5500.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/irqs-db8500.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/include/mach/uncompress.h
arch/arm/mach-ux500/pins-db8500.h [new file with mode: 0644]
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/pci.c
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
arch/arm/mach-vexpress/v2m.c
arch/arm/mach-w90x900/dev.c
arch/arm/mach-w90x900/include/mach/regs-gcr.h [new file with mode: 0644]
arch/arm/mach-w90x900/mach-nuc950evb.c
arch/arm/mach-w90x900/nuc910.c
arch/arm/mach-w90x900/nuc950.c
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/alignment.c
arch/arm/mm/cache-l2x0.c
arch/arm/mm/discontig.c [deleted file]
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault.c
arch/arm/mm/highmem.c
arch/arm/mm/init.c
arch/arm/mm/ioremap.c
arch/arm/mm/mm.h
arch/arm/mm/mmap.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm6_7.S
arch/arm/mm/proc-arm720.S
arch/arm/mm/proc-arm740.S
arch/arm/mm/proc-arm7tdmi.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-arm940.S
arch/arm/mm/proc-arm946.S
arch/arm/mm/proc-arm9tdmi.S
arch/arm/mm/proc-fa526.S
arch/arm/mm/proc-feroceon.S
arch/arm/mm/proc-mohawk.S
arch/arm/mm/proc-sa110.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/mm/vmregion.c
arch/arm/mm/vmregion.h
arch/arm/plat-iop/pci.c
arch/arm/plat-iop/time.c
arch/arm/plat-mxc/3ds_debugboard.c [new file with mode: 0644]
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/audmux-v1.c
arch/arm/plat-mxc/audmux-v2.c
arch/arm/plat-mxc/clock.c
arch/arm/plat-mxc/devices.c
arch/arm/plat-mxc/devices/Kconfig [new file with mode: 0644]
arch/arm/plat-mxc/devices/Makefile [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-flexcan.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-imx-i2c.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-imx-uart.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-mxc_nand.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-spi_imx.c [new file with mode: 0644]
arch/arm/plat-mxc/ehci.c
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/include/mach/3ds_debugboard.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-armadillo5x0.h [deleted file]
arch/arm/plat-mxc/include/mach/board-kzmarm11.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx21ads.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx27ads.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx27lite.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx27pdk.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx31_3ds.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx31ads.h [deleted file]
arch/arm/plat-mxc/include/mach/board-mx31lilly.h
arch/arm/plat-mxc/include/mach/board-mx31lite.h
arch/arm/plat-mxc/include/mach/board-mx31moboard.h
arch/arm/plat-mxc/include/mach/board-pcm038.h
arch/arm/plat-mxc/include/mach/board-qong.h [deleted file]
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/devices-common.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/eukrea-baseboards.h [moved from arch/arm/plat-mxc/include/mach/board-eukrea_cpuimx27.h with 64% similarity]
arch/arm/plat-mxc/include/mach/gpio.h
arch/arm/plat-mxc/include/mach/iomux-mx25.h
arch/arm/plat-mxc/include/mach/iomux-mx51.h
arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
arch/arm/plat-mxc/include/mach/iomux-v3.h
arch/arm/plat-mxc/include/mach/memory.h
arch/arm/plat-mxc/include/mach/mmc.h
arch/arm/plat-mxc/include/mach/mx1.h
arch/arm/plat-mxc/include/mach/mx25.h
arch/arm/plat-mxc/include/mach/mx27.h
arch/arm/plat-mxc/include/mach/mx2_cam.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/mx31.h
arch/arm/plat-mxc/include/mach/mx35.h
arch/arm/plat-mxc/include/mach/mx3_camera.h
arch/arm/plat-mxc/include/mach/mxc91231.h
arch/arm/plat-mxc/include/mach/mxc_nand.h
arch/arm/plat-mxc/include/mach/system.h
arch/arm/plat-mxc/include/mach/timex.h
arch/arm/plat-mxc/include/mach/uncompress.h
arch/arm/plat-mxc/include/mach/vmalloc.h
arch/arm/plat-mxc/irq.c
arch/arm/plat-mxc/system.c
arch/arm/plat-mxc/tzic.c
arch/arm/plat-nomadik/gpio.c
arch/arm/plat-nomadik/include/plat/gpio.h
arch/arm/plat-nomadik/include/plat/mtu.h
arch/arm/plat-nomadik/include/plat/pincfg.h [new file with mode: 0644]
arch/arm/plat-nomadik/timer.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/fb.c
arch/arm/plat-omap/include/plat/common.h
arch/arm/plat-omap/include/plat/vram.h
arch/arm/plat-orion/pcie.c
arch/arm/plat-samsung/include/plat/keypad.h [new file with mode: 0644]
arch/arm/plat-spear/time.c
arch/arm/plat-versatile/Makefile
arch/arm/plat-versatile/leds.c [new file with mode: 0644]
arch/arm/vfp/vfpmodule.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/time.c
arch/sh/boards/mach-ap325rxa/setup.c
drivers/amba/bus.c
drivers/char/keyboard.c
drivers/gpio/pl061.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/input/evdev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/matrix_keypad.c
drivers/input/keyboard/mcs_touchkey.c [new file with mode: 0644]
drivers/input/keyboard/samsung-keypad.c [new file with mode: 0644]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/adxl34x-i2c.c [new file with mode: 0644]
drivers/input/misc/adxl34x-spi.c [new file with mode: 0644]
drivers/input/misc/adxl34x.c [new file with mode: 0644]
drivers/input/misc/adxl34x.h [new file with mode: 0644]
drivers/input/misc/atlas_btns.c
drivers/input/misc/pwm-beeper.c [new file with mode: 0644]
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/misc/wistron_btns.c
drivers/input/mouse/bcm5974.c
drivers/input/mouse/synaptics.c
drivers/input/mousedev.c
drivers/input/serio/i8042-ppcio.h
drivers/input/serio/i8042.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7879-i2c.c [new file with mode: 0644]
drivers/input/touchscreen/ad7879-spi.c [new file with mode: 0644]
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/ad7879.h [new file with mode: 0644]
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/cy8ctmg110_ts.c [new file with mode: 0644]
drivers/input/touchscreen/mcs5000_ts.c
drivers/input/touchscreen/qt602240_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-ns2.c [new file with mode: 0644]
drivers/media/IR/Kconfig
drivers/media/IR/Makefile
drivers/media/IR/imon.c
drivers/media/IR/ir-core-priv.h
drivers/media/IR/ir-jvc-decoder.c
drivers/media/IR/ir-keytable.c
drivers/media/IR/ir-lirc-codec.c [new file with mode: 0644]
drivers/media/IR/ir-nec-decoder.c
drivers/media/IR/ir-raw-event.c
drivers/media/IR/ir-rc5-decoder.c
drivers/media/IR/ir-rc6-decoder.c
drivers/media/IR/ir-sony-decoder.c
drivers/media/IR/ir-sysfs.c
drivers/media/IR/keymaps/Makefile
drivers/media/IR/keymaps/rc-dib0700-nec.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-dib0700-rc5.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-lirc.c [new file with mode: 0644]
drivers/media/IR/keymaps/rc-rc6-mce.c [new file with mode: 0644]
drivers/media/IR/lirc_dev.c [new file with mode: 0644]
drivers/media/IR/mceusb.c [new file with mode: 0644]
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/af9005-remote.c
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/af9005.h
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/az6027.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c
drivers/media/dvb/dvb-usb/cxusb.c
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/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb-mc.c
drivers/media/dvb/dvb-usb/dibusb.h
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-init.c
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/gp8psk-fe.c
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/af9013.h
drivers/media/dvb/frontends/af9013_priv.h
drivers/media/dvb/frontends/dib3000mb.c
drivers/media/dvb/frontends/dib3000mb_priv.h
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/lgdt3305.c
drivers/media/dvb/frontends/lgdt3305.h
drivers/media/dvb/frontends/lgs8gxx.c
drivers/media/dvb/frontends/mb86a16.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/mantis/Kconfig
drivers/media/dvb/mantis/mantis_input.c
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/siano/sms-cards.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smsir.c
drivers/media/dvb/siano/smsir.h
drivers/media/dvb/siano/smsusb.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si4713-i2c.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/ak881x.c
drivers/media/video/au0828/Makefile
drivers/media/video/au0828/au0828-vbi.c [new file with mode: 0644]
drivers/media/video/au0828/au0828-video.c
drivers/media/video/au0828/au0828.h
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/cpia_usb.c
drivers/media/video/cx18/cx18-ioctl.c
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-ir.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-core.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dabusb.c
drivers/media/video/davinci/Kconfig [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/fsl-viu.c [new file with mode: 0644]
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/gl860/gl860-mi2020.c
drivers/media/video/gspca/gl860/gl860-ov9655.c
drivers/media/video/gspca/gl860/gl860.c
drivers/media/video/gspca/gl860/gl860.h
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jeilinj.c
drivers/media/video/gspca/m5602/m5602_bridge.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/pac7302.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca1528.c [new file with mode: 0644]
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/sq930x.c [new file with mode: 0644]
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv06xx/stv06xx.h
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/w996Xcf.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-firmware.h
drivers/media/video/ivtv/ivtv-mailbox.c
drivers/media/video/ivtv/ivtv-mailbox.h
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-version.h
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t112.c
drivers/media/video/mx2_camera.c [new file with mode: 0644]
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap24xxcam.c
drivers/media/video/ov511.c [deleted file]
drivers/media/video/ov511.h [deleted file]
drivers/media/video/ov772x.c
drivers/media/video/ov9640.c
drivers/media/video/ovcamchip/Makefile [deleted file]
drivers/media/video/ovcamchip/ov6x20.c [deleted file]
drivers/media/video/ovcamchip/ov6x30.c [deleted file]
drivers/media/video/ovcamchip/ov76be.c [deleted file]
drivers/media/video/ovcamchip/ov7x10.c [deleted file]
drivers/media/video/ovcamchip/ov7x20.c [deleted file]
drivers/media/video/ovcamchip/ovcamchip_core.c [deleted file]
drivers/media/video/ovcamchip/ovcamchip_priv.h [deleted file]
drivers/media/video/pvrusb2/pvrusb2-ioread.c
drivers/media/video/pxa_camera.c
drivers/media/video/rj54n1cb0c.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_mobile_csi2.c [new file with mode: 0644]
drivers/media/video/sh_vou.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/soc_mediabus.c
drivers/media/video/stv680.c [deleted file]
drivers/media/video/stv680.h [deleted file]
drivers/media/video/tlg2300/pd-main.c
drivers/media/video/tw9910.c
drivers/media/video/usbvideo/Kconfig
drivers/media/video/usbvideo/Makefile
drivers/media/video/usbvideo/quickcam_messenger.c [deleted file]
drivers/media/video/usbvideo/quickcam_messenger.h [deleted file]
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-dev.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videobuf-vmalloc.c
drivers/media/video/w9968cf.c [deleted file]
drivers/media/video/w9968cf.h [deleted file]
drivers/media/video/w9968cf_decoder.h [deleted file]
drivers/media/video/w9968cf_vpp.h [deleted file]
drivers/media/video/zc0301/Kconfig [deleted file]
drivers/media/video/zc0301/Makefile [deleted file]
drivers/media/video/zc0301/zc0301.h [deleted file]
drivers/media/video/zc0301/zc0301_core.c [deleted file]
drivers/media/video/zc0301/zc0301_pas202bcb.c [deleted file]
drivers/media/video/zc0301/zc0301_pb0330.c [deleted file]
drivers/media/video/zc0301/zc0301_sensor.h [deleted file]
drivers/media/video/zoran/videocodec.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/arm-charlcd.c [new file with mode: 0644]
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/mxcmmc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/scan.h
drivers/mtd/ubi/ubi.h
drivers/net/phy/marvell.c
drivers/parisc/led.c
drivers/rtc/rtc-pl031.c
drivers/serial/amba-pl010.c
drivers/serial/amba-pl011.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/cx25821/Makefile
drivers/staging/cx25821/cx25821-alsa.c
drivers/staging/cx25821/cx25821-audio-upstream.c
drivers/staging/cx25821/cx25821-audio.h
drivers/staging/cx25821/cx25821-audups11.c [deleted file]
drivers/staging/cx25821/cx25821-core.c
drivers/staging/cx25821/cx25821-i2c.c
drivers/staging/cx25821/cx25821-medusa-defines.h
drivers/staging/cx25821/cx25821-medusa-reg.h
drivers/staging/cx25821/cx25821-medusa-video.c
drivers/staging/cx25821/cx25821-medusa-video.h
drivers/staging/cx25821/cx25821-reg.h
drivers/staging/cx25821/cx25821-sram.h
drivers/staging/cx25821/cx25821-video-upstream-ch2.c
drivers/staging/cx25821/cx25821-video-upstream-ch2.h
drivers/staging/cx25821/cx25821-video-upstream.c
drivers/staging/cx25821/cx25821-video-upstream.h
drivers/staging/cx25821/cx25821-video.c
drivers/staging/cx25821/cx25821-video.h
drivers/staging/cx25821/cx25821-video0.c [deleted file]
drivers/staging/cx25821/cx25821-video1.c [deleted file]
drivers/staging/cx25821/cx25821-video2.c [deleted file]
drivers/staging/cx25821/cx25821-video3.c [deleted file]
drivers/staging/cx25821/cx25821-video4.c [deleted file]
drivers/staging/cx25821/cx25821-video5.c [deleted file]
drivers/staging/cx25821/cx25821-video6.c [deleted file]
drivers/staging/cx25821/cx25821-video7.c [deleted file]
drivers/staging/cx25821/cx25821-videoioctl.c [deleted file]
drivers/staging/cx25821/cx25821-vidups10.c [deleted file]
drivers/staging/cx25821/cx25821-vidups9.c [deleted file]
drivers/staging/cx25821/cx25821.h
drivers/staging/lirc/Kconfig [new file with mode: 0644]
drivers/staging/lirc/Makefile [new file with mode: 0644]
drivers/staging/lirc/TODO [new file with mode: 0644]
drivers/staging/lirc/TODO.lirc_i2c [new file with mode: 0644]
drivers/staging/lirc/lirc_bt829.c [new file with mode: 0644]
drivers/staging/lirc/lirc_ene0100.c [new file with mode: 0644]
drivers/staging/lirc/lirc_ene0100.h [new file with mode: 0644]
drivers/staging/lirc/lirc_i2c.c [new file with mode: 0644]
drivers/staging/lirc/lirc_igorplugusb.c [new file with mode: 0644]
drivers/staging/lirc/lirc_imon.c [new file with mode: 0644]
drivers/staging/lirc/lirc_it87.c [new file with mode: 0644]
drivers/staging/lirc/lirc_it87.h [new file with mode: 0644]
drivers/staging/lirc/lirc_ite8709.c [new file with mode: 0644]
drivers/staging/lirc/lirc_parallel.c [new file with mode: 0644]
drivers/staging/lirc/lirc_parallel.h [new file with mode: 0644]
drivers/staging/lirc/lirc_sasem.c [new file with mode: 0644]
drivers/staging/lirc/lirc_serial.c [new file with mode: 0644]
drivers/staging/lirc/lirc_sir.c [new file with mode: 0644]
drivers/staging/lirc/lirc_streamzap.c [new file with mode: 0644]
drivers/staging/lirc/lirc_ttusbir.c [new file with mode: 0644]
drivers/staging/lirc/lirc_zilog.c [new file with mode: 0644]
drivers/staging/tm6000/Kconfig
drivers/staging/tm6000/Makefile
drivers/staging/tm6000/tm6000-alsa.c
drivers/staging/tm6000/tm6000-cards.c
drivers/staging/tm6000/tm6000-core.c
drivers/staging/tm6000/tm6000-dvb.c
drivers/staging/tm6000/tm6000-i2c.c
drivers/staging/tm6000/tm6000-input.c [new file with mode: 0644]
drivers/staging/tm6000/tm6000-stds.c
drivers/staging/tm6000/tm6000-usb-isoc.h
drivers/staging/tm6000/tm6000-video.c
drivers/staging/tm6000/tm6000.h
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/at91_udc.h
drivers/usb/gadget/f_uvc.c
drivers/usb/gadget/f_uvc.h
drivers/usb/gadget/fsl_mxc_udc.c
drivers/usb/gadget/uvc.h
drivers/usb/gadget/webcam.c
drivers/usb/host/ehci-mxc.c
drivers/video/cyber2000fb.c
drivers/video/imxfb.c
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/vram.c
fs/9p/Makefile
fs/9p/fid.c
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/v9fs_vfs.h
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/9p/xattr.c [new file with mode: 0644]
fs/9p/xattr.h [new file with mode: 0644]
fs/9p/xattr_user.c [new file with mode: 0644]
fs/cifs/Kconfig
fs/cifs/Makefile
fs/cifs/cache.c [new file with mode: 0644]
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_spnego.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/dns_resolve.c
fs/cifs/dns_resolve.h
fs/cifs/file.c
fs/cifs/fscache.c [new file with mode: 0644]
fs/cifs/fscache.h [new file with mode: 0644]
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/smberr.h
fs/direct-io.c
fs/ext4/inode.c
fs/fuse/dir.c
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/bmap.h
fs/gfs2/dir.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/incore.h
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/super.c
fs/gfs2/sys.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/nfsroot.c
fs/nfs/write.c
fs/ocfs2/aops.c
fs/open.c
fs/proc/array.c
fs/ubifs/lpt.c
fs/ubifs/lpt_commit.c
fs/ubifs/recovery.c
fs/ubifs/super.c
fs/xfs/Makefile
fs/xfs/linux-2.6/xfs_acl.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_aops.h
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_buf.h
fs/xfs/linux-2.6/xfs_dmapi_priv.h [deleted file]
fs/xfs/linux-2.6/xfs_export.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_fs_subr.c
fs/xfs/linux-2.6/xfs_fs_subr.h [deleted file]
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_ioctl32.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_quotaops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_super.h
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/linux-2.6/xfs_sync.h
fs/xfs/linux-2.6/xfs_trace.c
fs/xfs/linux-2.6/xfs_trace.h
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_stats.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/quota/xfs_trans_dquot.c
fs/xfs/support/debug.c
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_alloc_btree.c
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_bmap_btree.c
fs/xfs/xfs_btree.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_buf_item.h
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dir2.c
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dir2_data.c
fs/xfs/xfs_dir2_leaf.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_dmapi.h [deleted file]
fs/xfs/xfs_dmops.c [deleted file]
fs/xfs/xfs_error.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_filestream.h
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_ialloc_btree.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iomap.h
fs/xfs/xfs_itable.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_rename.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rw.c
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_extfree.c
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_trans_item.c [deleted file]
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_utils.c
fs/xfs/xfs_utils.h
fs/xfs/xfs_vnodeops.c
include/linux/amba/bus.h
include/linux/amba/mmci.h
include/linux/amba/serial.h
include/linux/capability.h
include/linux/cred.h
include/linux/dvb/frontend.h
include/linux/dvb/version.h
include/linux/fs.h
include/linux/i2c/adp5588.h
include/linux/i2c/mcs.h [new file with mode: 0644]
include/linux/i2c/mcs5000_ts.h [deleted file]
include/linux/i2c/qt602240_ts.h [new file with mode: 0644]
include/linux/input.h
include/linux/input/adxl34x.h [new file with mode: 0644]
include/linux/input/cy8ctmg110_pdata.h [new file with mode: 0644]
include/linux/input/matrix_keypad.h
include/linux/lsm_audit.h
include/linux/marvell_phy.h [new file with mode: 0644]
include/linux/nfs_fs.h
include/linux/omapfb.h
include/linux/sched.h
include/linux/security.h
include/linux/spi/ads7846.h
include/linux/swiotlb.h
include/linux/usb/video.h
include/linux/virtio_9p.h
include/linux/xattr.h
include/media/ir-core.h
include/media/ir-kbd-i2c.h
include/media/lirc.h [new file with mode: 0644]
include/media/lirc_dev.h [new file with mode: 0644]
include/media/rc-map.h
include/media/sh_mobile_ceu.h
include/media/sh_mobile_csi2.h [new file with mode: 0644]
include/media/soc_camera.h
include/media/v4l2-mediabus.h
include/media/videobuf-core.h
include/media/videobuf-dma-sg.h
include/media/videobuf-vmalloc.h
include/net/9p/9p.h
include/net/9p/client.h
kernel/cred.c
lib/atomic64_test.c
lib/swiotlb.c
mm/memory.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_fd.c
security/Kconfig
security/Makefile
security/apparmor/.gitignore [new file with mode: 0644]
security/apparmor/Kconfig [new file with mode: 0644]
security/apparmor/Makefile [new file with mode: 0644]
security/apparmor/apparmorfs.c [new file with mode: 0644]
security/apparmor/audit.c [new file with mode: 0644]
security/apparmor/capability.c [new file with mode: 0644]
security/apparmor/context.c [new file with mode: 0644]
security/apparmor/domain.c [new file with mode: 0644]
security/apparmor/file.c [new file with mode: 0644]
security/apparmor/include/apparmor.h [new file with mode: 0644]
security/apparmor/include/apparmorfs.h [new file with mode: 0644]
security/apparmor/include/audit.h [new file with mode: 0644]
security/apparmor/include/capability.h [new file with mode: 0644]
security/apparmor/include/context.h [new file with mode: 0644]
security/apparmor/include/domain.h [new file with mode: 0644]
security/apparmor/include/file.h [new file with mode: 0644]
security/apparmor/include/ipc.h [new file with mode: 0644]
security/apparmor/include/match.h [new file with mode: 0644]
security/apparmor/include/path.h [new file with mode: 0644]
security/apparmor/include/policy.h [new file with mode: 0644]
security/apparmor/include/policy_unpack.h [new file with mode: 0644]
security/apparmor/include/procattr.h [new file with mode: 0644]
security/apparmor/include/resource.h [new file with mode: 0644]
security/apparmor/include/sid.h [new file with mode: 0644]
security/apparmor/ipc.c [new file with mode: 0644]
security/apparmor/lib.c [new file with mode: 0644]
security/apparmor/lsm.c [new file with mode: 0644]
security/apparmor/match.c [new file with mode: 0644]
security/apparmor/path.c [new file with mode: 0644]
security/apparmor/policy.c [new file with mode: 0644]
security/apparmor/policy_unpack.c [new file with mode: 0644]
security/apparmor/procattr.c [new file with mode: 0644]
security/apparmor/resource.c [new file with mode: 0644]
security/apparmor/sid.c [new file with mode: 0644]
security/capability.c
security/inode.c
security/integrity/ima/ima_fs.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/selinux/netnode.c
security/selinux/selinuxfs.c
security/selinux/ss/avtab.c
security/selinux/ss/conditional.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/selinux/ss/symtab.c
security/smack/smack.h
security/smack/smack_lsm.c
security/tomoyo/Makefile
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/gc.c
security/tomoyo/group.c [new file with mode: 0644]
security/tomoyo/load_policy.c [new file with mode: 0644]
security/tomoyo/memory.c [new file with mode: 0644]
security/tomoyo/mount.c [new file with mode: 0644]
security/tomoyo/path_group.c [deleted file]
security/tomoyo/realpath.c
security/tomoyo/securityfs_if.c [new file with mode: 0644]
security/tomoyo/tomoyo.c
security/tomoyo/util.c [new file with mode: 0644]
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_nvhdmi.c
sound/pci/hda/patch_realtek.c
tools/perf/arch/arm/Makefile [new file with mode: 0644]
tools/perf/arch/arm/util/dwarf-regs.c [new file with mode: 0644]

index 63c528fee624a3f17fecd204f6212a1302a859c0..e3a97fdd62a6b85bf3f705d39de39719a16221dc 100644 (file)
 <othername role="mi">O. C.</othername>
 <affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
 </author>
+</authorgroup>
+<authorgroup>
 <author>
 <firstname>Mauro</firstname>
-<surname>Chehab</surname>
 <othername role="mi">Carvalho</othername>
+<surname>Chehab</surname>
 <affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
 <contrib>Ported document to Docbook XML.</contrib>
 </author>
 <copyright>
        <year>2002</year>
        <year>2003</year>
-       <year>2009</year>
        <holder>Convergence GmbH</holder>
 </copyright>
+<copyright>
+       <year>2009-2010</year>
+       <holder>Mauro Carvalho Chehab</holder>
+</copyright>
 
 <revhistory>
 <!-- Put document revisions here, newest first. -->
+<revision>
+       <revnumber>2.0.3</revnumber>
+       <date>2010-07-03</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>
+               Add some frontend capabilities flags, present on kernel, but missing at the specs.
+       </revremark>
+</revision>
 <revision>
        <revnumber>2.0.2</revnumber>
        <date>2009-10-25</date>
@@ -63,7 +76,7 @@ Added ISDB-T test originally written by Patrick Boettcher
 
 
 <title>LINUX DVB API</title>
-<subtitle>Version 3</subtitle>
+<subtitle>Version 5.2</subtitle>
 <!-- ADD THE CHAPTERS HERE -->
   <chapter id="dvb_introdution">
     &sub-intro;
index b99644f5340a3f195ba9fcec9b10e50a7538a270..d08e0d401418686540d30a0871feea0a8065a046 100644 (file)
@@ -63,6 +63,7 @@ typedef enum fe_caps {
         FE_CAN_8VSB                     = 0x200000,
         FE_CAN_16VSB                    = 0x400000,
         FE_HAS_EXTENDED_CAPS            = 0x800000,   /* We need more bitspace for newer APIs, indicate this. */
+        FE_CAN_TURBO_FEC                = 0x8000000,  /* frontend supports "turbo fec modulation" */
         FE_CAN_2G_MODULATION            = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
         FE_NEEDS_BENDING                = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
         FE_CAN_RECOVER                  = 0x40000000, /* frontend can recover from a cable unplug automatically */
index 300ba1f0417789178ef562932db03d0ed4912673..78d756de5906ecbee16b2b8976b7550e22d8aa03 100644 (file)
@@ -64,8 +64,14 @@ a specific frontend type.</para>
        FE_CAN_BANDWIDTH_AUTO         = 0x40000,
        FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
        FE_CAN_HIERARCHY_AUTO         = 0x100000,
-       FE_CAN_MUTE_TS                = 0x80000000,
-       FE_CAN_CLEAN_SETUP            = 0x40000000
+       FE_CAN_8VSB                   = 0x200000,
+       FE_CAN_16VSB                  = 0x400000,
+       FE_HAS_EXTENDED_CAPS          = 0x800000,
+       FE_CAN_TURBO_FEC              = 0x8000000,
+       FE_CAN_2G_MODULATION          = 0x10000000,
+       FE_NEEDS_BENDING              = 0x20000000,
+       FE_CAN_RECOVER                = 0x40000000,
+       FE_CAN_MUTE_TS                = 0x80000000
        } fe_caps_t;
 </programlisting>
 </section>
index 5d4d40f429a5411c289cd3924c5ad583ffbae7b4..6ae97157b1c7eeac834207e24dba66e865760c57 100644 (file)
 <!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-lirc_device_interface SYSTEM "v4l/lirc_device_interface.xml">
 <!ENTITY sub-remote_controllers SYSTEM "v4l/remote_controllers.xml">
 <!ENTITY sub-fdl-appendix SYSTEM "v4l/fdl-appendix.xml">
 <!ENTITY sub-close SYSTEM "v4l/func-close.xml">
index eea564bb12cb4a620032978c150d113ef7ff6e7f..f11048d4053f01725d762788ee4b9ebe647ced11 100644 (file)
@@ -28,7 +28,7 @@
 <title>LINUX MEDIA INFRASTRUCTURE API</title>
 
 <copyright>
-       <year>2009</year>
+       <year>2009-2010</year>
        <holder>LinuxTV Developers</holder>
 </copyright>
 
@@ -61,7 +61,7 @@ Foundation. A copy of the license is included in the chapter entitled
                in fact it covers several different video standards including
                DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
                to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
-       <para>The third part covers other API's used by all media infrastructure devices</para>
+       <para>The third part covers Remote Controller API</para>
        <para>For additional information and for the latest development code,
                see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
        <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled
 </author>
 </authorgroup>
 <copyright>
-       <year>2009</year>
+       <year>2009-2010</year>
        <holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
@@ -101,7 +101,7 @@ Foundation. A copy of the license is included in the chapter entitled
 </revhistory>
 </partinfo>
 
-<title>Other API's used by media infrastructure drivers</title>
+<title>Remote Controller API</title>
 <chapter id="remote_controllers">
 &sub-remote_controllers;
 </chapter>
diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml
new file mode 100644 (file)
index 0000000..0413234
--- /dev/null
@@ -0,0 +1,235 @@
+<section id="lirc_dev">
+<title>LIRC Device Interface</title>
+
+
+<section id="lirc_dev_intro">
+<title>Introduction</title>
+
+<para>The LIRC device interface is a bi-directional interface for
+transporting raw IR data between userspace and kernelspace. Fundamentally,
+it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number
+of standard struct file_operations defined on it. With respect to
+transporting raw IR data to and fro, the essential fops are read, write
+and ioctl.</para>
+
+<para>Example dmesg output upon a driver registering w/LIRC:</para>
+  <blockquote>
+    <para>$ dmesg |grep lirc_dev</para>
+    <para>lirc_dev: IR Remote Control driver registered, major 248</para>
+    <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para>
+  </blockquote>
+
+<para>What you should see for a chardev:</para>
+  <blockquote>
+    <para>$ ls -l /dev/lirc*</para>
+    <para>crw-rw---- 1 root root 248, 0 Jul  2 22:20 /dev/lirc0</para>
+  </blockquote>
+</section>
+
+<section id="lirc_read">
+<title>LIRC read fop</title>
+
+<para>The lircd userspace daemon reads raw IR data from the LIRC chardev. The
+exact format of the data depends on what modes a driver supports, and what
+mode has been selected. lircd obtains supported modes and sets the active mode
+via the ioctl interface, detailed at <xref linkend="lirc_ioctl"/>. The generally
+preferred mode is LIRC_MODE_MODE2, in which packets containing an int value
+describing an IR signal are read from the chardev.</para>
+
+<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para>
+</section>
+
+<section id="lirc_write">
+<title>LIRC write fop</title>
+
+<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
+been transmitted by the hardware.</para>
+</section>
+
+<section id="lirc_ioctl">
+<title>LIRC ioctl fop</title>
+
+<para>The LIRC device's ioctl definition is bound by the ioctl function
+definition of struct file_operations, leaving us with an unsigned int
+for the ioctl command and an unsigned long for the arg. For the purposes
+of ioctl portability across 32-bit and 64-bit, these values are capped
+to their 32-bit sizes.</para>
+
+<para>The following ioctls can be used to change specific hardware settings.
+In general each driver should have a default set of settings. The driver
+implementation is expected to re-apply the default settings when the device
+is closed by user-space, so that every application opening the device can rely
+on working with the default settings initially.</para>
+
+<variablelist>
+  <varlistentry>
+    <term>LIRC_GET_FEATURES</term>
+    <listitem>
+      <para>Obviously, get the underlying hardware device's features. If a driver
+      does not announce support of certain features, calling of the corresponding
+      ioctls is undefined.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_SEND_MODE</term>
+    <listitem>
+      <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_MODE</term>
+    <listitem>
+      <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE
+      are supported by lircd.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_SEND_CARRIER</term>
+    <listitem>
+      <para>Get carrier frequency (in Hz) currently used for transmit.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_CARRIER</term>
+    <listitem>
+      <para>Get carrier frequency (in Hz) currently used for IR reception.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term>
+    <listitem>
+      <para>Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently,
+      no special meaning is defined for 0 or 100, but this could be used to switch
+      off carrier generation in the future, so these values should be reserved.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_RESOLUTION</term>
+    <listitem>
+      <para>Some receiver have maximum resolution which is defined by internal
+      sample rate or data format limitations. E.g. it's common that signals can
+      only be reported in 50 microsecond steps. This integer value is used by
+      lircd to automatically adjust the aeps tolerance value in the lircd
+      config file.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_M{IN,AX}_TIMEOUT</term>
+    <listitem>
+      <para>Some devices have internal timers that can be used to detect when
+      there's no IR activity for a long time. This can help lircd in detecting
+      that a IR signal is finished and can speed up the decoding process.
+      Returns an integer value with the minimum/maximum timeout that can be
+      set. Some devices have a fixed timeout, in that case both ioctls will
+      return the same value even though the timeout cannot be changed.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term>
+    <listitem>
+      <para>Some devices are able to filter out spikes in the incoming signal
+      using given filter rules. These ioctls return the hardware capabilities
+      that describe the bounds of the possible filters. Filter settings depend
+      on the IR protocols that are expected. lircd derives the settings from
+      all protocols definitions found in its config file.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_LENGTH</term>
+    <listitem>
+      <para>Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE).
+      Reads on the device must be done in blocks matching the bit count.
+      The bit could should be rounded up so that it matches full bytes.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_{SEND,REC}_MODE</term>
+    <listitem>
+      <para>Set send/receive mode. Largely obsolete for send, as only
+      LIRC_MODE_PULSE is supported.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_{SEND,REC}_CARRIER</term>
+    <listitem>
+      <para>Set send/receive carrier (in Hz).</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_TRANSMITTER_MASK</term>
+    <listitem>
+      <para>This enables the given set of transmitters. The first transmitter
+      is encoded by the least significant bit, etc. When an invalid bit mask
+      is given, i.e. a bit is set, even though the device does not have so many
+      transitters, then this ioctl returns the number of available transitters
+      and does nothing otherwise.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_TIMEOUT</term>
+    <listitem>
+      <para>Sets the integer value for IR inactivity timeout (cf.
+      LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if
+      supported by the hardware) disables all hardware timeouts and data should
+      be reported as soon as possible. If the exact value cannot be set, then
+      the next possible value _greater_ than the given value should be set.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_TIMEOUT_REPORTS</term>
+    <listitem>
+      <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By
+      default, timeout reports should be turned off.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term>
+    <listitem>
+      <para>Pulses/spaces shorter than this are filtered out by hardware. If
+      filters cannot be set independently for pulse/space, the corresponding
+      ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_MEASURE_CARRIER_MODE</term>
+    <listitem>
+      <para>Enable (1)/disable (0) measure mode. If enabled, from the next key
+      press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default
+      this should be turned off.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term>
+    <listitem>
+      <para>To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE
+      with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER
+      with the upper bound.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_NOTIFY_DECODE</term>
+    <listitem>
+      <para>This ioctl is called by lircd whenever a successful decoding of an
+      incoming IR signal could be done. This can be used by supporting hardware
+      to give visual feedback to the user e.g. by flashing a LED.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SETUP_{START,END}</term>
+    <listitem>
+      <para>Setting of several driver parameters can be optimized by encapsulating
+      the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a
+      driver receives a LIRC_SETUP_START ioctl it can choose to not commit
+      further setting changes to the hardware until a LIRC_SETUP_END is received.
+      But this is open to the driver implementation and every driver must also
+      handle parameter changes which are not encapsulated by LIRC_SETUP_START
+      and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls.</para>
+    </listitem>
+  </varlistentry>
+</variablelist>
+
+</section>
+</section>
index 73f5eab091f4afaa0c6f333c82d8171c638567db..3c3b667b28e755d3b8e1233a16fcf76ac3657170 100644 (file)
@@ -173,3 +173,5 @@ keymapping.</para>
 <para>This program demonstrates how to replace the keymap tables.</para>
 &sub-keytable-c;
 </section>
+
+&sub-lirc_device_interface;
diff --git a/Documentation/apparmor.txt b/Documentation/apparmor.txt
new file mode 100644 (file)
index 0000000..93c1fd7
--- /dev/null
@@ -0,0 +1,39 @@
+--- What is AppArmor? ---
+
+AppArmor is MAC style security extension for the Linux kernel.  It implements
+a task centered policy, with task "profiles" being created and loaded
+from user space.  Tasks on the system that do not have a profile defined for
+them run in an unconfined state which is equivalent to standard Linux DAC
+permissions.
+
+--- How to enable/disable ---
+
+set CONFIG_SECURITY_APPARMOR=y
+
+If AppArmor should be selected as the default security module then
+   set CONFIG_DEFAULT_SECURITY="apparmor"
+   and CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
+
+Build the kernel
+
+If AppArmor is not the default security module it can be enabled by passing
+security=apparmor on the kernel's command line.
+
+If AppArmor is the default security module it can be disabled by passing
+apparmor=0, security=XXXX (where XXX is valid security module), on the
+kernel's command line
+
+For AppArmor to enforce any restrictions beyond standard Linux DAC permissions
+policy must be loaded into the kernel from user space (see the Documentation
+and tools links).
+
+--- Documentation ---
+
+Documentation can be found on the wiki.
+
+--- Links ---
+
+Mailing List - apparmor@lists.ubuntu.com
+Wiki - http://apparmor.wiki.kernel.org/
+User space tools - https://launchpad.net/apparmor
+Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
index eb0fae18ffb12a805bb81eb2c5005a773d499d2b..771d48d3b335a1419f1ec363d540c77ad6d75fbc 100644 (file)
@@ -33,7 +33,13 @@ ffff0000     ffff0fff        CPU vector page.
 
 fffe0000       fffeffff        XScale cache flush area.  This is used
                                in proc-xscale.S to flush the whole data
-                               cache.  Free for other usage on non-XScale.
+                               cache. (XScale does not have TCM.)
+
+fffe8000       fffeffff        DTCM mapping area for platforms with
+                               DTCM mounted inside the CPU.
+
+fffe0000       fffe7fff        ITCM mapping area for platforms with
+                               ITCM mounted inside the CPU.
 
 fff00000       fffdffff        Fixmap mapping region.  Addresses provided
                                by fix_to_virt() will be located here.
index 77fd9376e6d73b4cc47d39afb8d7b01ad4b00120..7c15871c1885df512a87493c8fbfc3c1df6cc610 100644 (file)
@@ -19,8 +19,8 @@ defines a CPUID_TCM register that you can read out from the
 system control coprocessor. Documentation from ARM can be found
 at http://infocenter.arm.com, search for "TCM Status Register"
 to see documents for all CPUs. Reading this register you can
-determine if ITCM (bit 0) and/or DTCM (bit 16) is present in the
-machine.
+determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present
+in the machine.
 
 There is further a TCM region register (search for "TCM Region
 Registers" at the ARM site) that can report and modify the location
@@ -35,7 +35,15 @@ The TCM memory can then be remapped to another address again using
 the MMU, but notice that the TCM if often used in situations where
 the MMU is turned off. To avoid confusion the current Linux
 implementation will map the TCM 1 to 1 from physical to virtual
-memory in the location specified by the machine.
+memory in the location specified by the kernel. Currently Linux
+will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and
+on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM.
+
+Newer versions of the region registers also support dividing these
+TCMs in two separate banks, so for example an 8KiB ITCM is divided
+into two 4KiB banks with its own control registers. The idea is to
+be able to lock and hide one of the banks for use by the secure
+world (TrustZone).
 
 TCM is used for a few things:
 
@@ -65,18 +73,18 @@ in <asm/tcm.h>. Using this interface it is possible to:
   memory. Such a heap is great for things like saving
   device state when shutting off device power domains.
 
-A machine that has TCM memory shall select HAVE_TCM in
-arch/arm/Kconfig for itself, and then the
-rest of the functionality will depend on the physical
-location and size of ITCM and DTCM to be defined in
-mach/memory.h for the machine. Code that needs to use
-TCM shall #include <asm/tcm.h> If the TCM is not located
-at the place given in memory.h it will be moved using
-the TCM Region registers.
+A machine that has TCM memory shall select HAVE_TCM from
+arch/arm/Kconfig for itself. Code that needs to use TCM shall
+#include <asm/tcm.h>
 
 Functions to go into itcm can be tagged like this:
 int __tcmfunc foo(int bar);
 
+Since these are marked to become long_calls and you may want
+to have functions called locally inside the TCM without
+wasting space, there is also the __tcmlocalfunc prefix that
+will make the call relative.
+
 Variables to go into dtcm can be tagged like this:
 int __tcmdata foo;
 
index a2db352870036ba062aa177ce450d0d491f7d8c8..995baf379c076770962a84268fde19b527caa0be 100644 (file)
@@ -417,6 +417,9 @@ reference on them using:
 This does all the RCU magic inside of it.  The caller must call put_cred() on
 the credentials so obtained when they're finished with.
 
+ [*] Note: The result of __task_cred() should not be passed directly to
+     get_cred() as this may race with commit_cred().
+
 There are a couple of convenience functions to access bits of another task's
 credentials, hiding the RCU magic from the caller:
 
index 239cbdbf4d120edc39869cd1af74764c01c4acbe..350959f4e41b414139abdb85d13d583e0eb18881 100644 (file)
@@ -26,7 +26,7 @@ use IO::Handle;
                "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
                "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
-               "af9015", "ngene");
+               "af9015", "ngene", "az6027");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -518,11 +518,11 @@ sub bluebird {
 sub af9015 {
        my $sourcefile = "download.ashx?file=57";
        my $url = "http://www.ite.com.tw/EN/Services/$sourcefile";
-       my $hash = "ff5b096ed47c080870eacdab2de33ad6";
+       my $hash = "e3f08935158038d385ad382442f4bb2d";
        my $outfile = "dvb-usb-af9015.fw";
        my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
-       my $fwoffset = 0x22708;
-       my $fwlength = 18225;
+       my $fwoffset = 0x25690;
+       my $fwlength = 18725;
        my ($chunklength, $buf, $rcount);
 
        checkstandard();
@@ -567,6 +567,23 @@ sub ngene {
     "$file1, $file2";
 }
 
+sub az6027{
+    my $file = "AZ6027_Linux_Driver.tar.gz";
+    my $url = "http://linux.terratec.de/files/$file";
+    my $firmware = "dvb-usb-az6027-03.fw";
+
+    wgetfile($file, $url);
+
+    #untar
+    if( system("tar xzvf $file $firmware")){
+        die "failed to untar firmware";
+    }
+    if( system("rm $file")){
+        die ("unable to remove unnecessary files");
+    }
+
+    $firmware;
+}
 # ---------------------------------------------------------------
 # Utilities
 
index 123ec0e237385c10277e260d1bab2d1e9d82d278..b273d35039eda59555e43485a68ea282aaf377af 100644 (file)
@@ -459,57 +459,6 @@ Who:       Corentin Chary <corentin.chary@gmail.com>
 
 ----------------------------
 
-What:  usbvideo quickcam_messenger driver
-When:  2.6.35
-Files: drivers/media/video/usbvideo/quickcam_messenger.[ch]
-Why:   obsolete v4l1 driver replaced by gspca_stv06xx
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  ov511 v4l1 driver
-When:  2.6.35
-Files: drivers/media/video/ov511.[ch]
-Why:   obsolete v4l1 driver replaced by gspca_ov519
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  w9968cf v4l1 driver
-When:  2.6.35
-Files: drivers/media/video/w9968cf*.[ch]
-Why:   obsolete v4l1 driver replaced by gspca_ov519
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  ovcamchip sensor framework
-When:  2.6.35
-Files: drivers/media/video/ovcamchip/*
-Why:   Only used by obsoleted v4l1 drivers
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  stv680 v4l1 driver
-When:  2.6.35
-Files: drivers/media/video/stv680.[ch]
-Why:   obsolete v4l1 driver replaced by gspca_stv0680
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  zc0301 v4l driver
-When:  2.6.35
-Files: drivers/media/video/zc0301/*
-Why:   Duplicate functionality with the gspca_zc3xx driver, zc0301 only
-       supports 2 USB-ID's (because it only supports a limited set of
-       sensors) wich are also supported by the gspca_zc3xx driver
-       (which supports 53 USB-ID's in total)
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
 What:  sysfs-class-rfkill state file
 When:  Feb 2014
 Files: net/rfkill/core.c
index 9878f50d6ed6d37b3241eb558a58d08681898927..7bff3e4f35df84a9def7507badb42ccdeffef419 100644 (file)
@@ -131,17 +131,6 @@ When mounting an XFS filesystem, the following options are accepted.
        Don't check for double mounted file systems using the file system uuid.
        This is useful to mount LVM snapshot volumes.
 
-  osyncisosync
-       Make O_SYNC writes implement true O_SYNC.  WITHOUT this option,
-       Linux XFS behaves as if an "osyncisdsync" option is used,
-       which will make writes to files opened with the O_SYNC flag set
-       behave as if the O_DSYNC flag had been used instead.
-       This can result in better performance without compromising
-       data safety.
-       However if this option is not in effect, timestamp updates from
-       O_SYNC writes can be lost if the system crashes.
-       If timestamp updates are critical, use the osyncisosync option.
-
   uquota/usrquota/uqnoenforce/quota
        User disk quota accounting enabled, and limits (optionally)
        enforced.  Refer to xfs_quota(8) for further details.
index c0fc1c75fd88654ad7dc3a901381bf01124cdca7..bdcba154b83e1ec72ee7692131abfdcf320b268a 100644 (file)
@@ -6,31 +6,149 @@ Multi-touch (MT) Protocol
 Introduction
 ------------
 
-In order to utilize the full power of the new multi-touch devices, a way to
-report detailed finger data to user space is needed. This document
-describes the multi-touch (MT) protocol which allows kernel drivers to
-report details for an arbitrary number of fingers.
+In order to utilize the full power of the new multi-touch and multi-user
+devices, a way to report detailed data from multiple contacts, i.e.,
+objects in direct contact with the device surface, is needed.  This
+document describes the multi-touch (MT) protocol which allows kernel
+drivers to report details for an arbitrary number of contacts.
+
+The protocol is divided into two types, depending on the capabilities of the
+hardware. For devices handling anonymous contacts (type A), the protocol
+describes how to send the raw data for all contacts to the receiver. For
+devices capable of tracking identifiable contacts (type B), the protocol
+describes how to send updates for individual contacts via event slots.
+
+
+Protocol Usage
+--------------
+
+Contact details are sent sequentially as separate packets of ABS_MT
+events. Only the ABS_MT events are recognized as part of a contact
+packet. Since these events are ignored by current single-touch (ST)
+applications, the MT protocol can be implemented on top of the ST protocol
+in an existing driver.
+
+Drivers for type A devices separate contact packets by calling
+input_mt_sync() at the end of each packet. This generates a SYN_MT_REPORT
+event, which instructs the receiver to accept the data for the current
+contact and prepare to receive another.
+
+Drivers for type B devices separate contact packets by calling
+input_mt_slot(), with a slot as argument, at the beginning of each packet.
+This generates an ABS_MT_SLOT event, which instructs the receiver to
+prepare for updates of the given slot.
+
+All drivers mark the end of a multi-touch transfer by calling the usual
+input_sync() function. This instructs the receiver to act upon events
+accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new set
+of events/packets.
+
+The main difference between the stateless type A protocol and the stateful
+type B slot protocol lies in the usage of identifiable contacts to reduce
+the amount of data sent to userspace. The slot protocol requires the use of
+the ABS_MT_TRACKING_ID, either provided by the hardware or computed from
+the raw data [5].
+
+For type A devices, the kernel driver should generate an arbitrary
+enumeration of the full set of anonymous contacts currently on the
+surface. The order in which the packets appear in the event stream is not
+important.  Event filtering and finger tracking is left to user space [3].
+
+For type B devices, the kernel driver should associate a slot with each
+identified contact, and use that slot to propagate changes for the contact.
+Creation, replacement and destruction of contacts is achieved by modifying
+the ABS_MT_TRACKING_ID of the associated slot.  A non-negative tracking id
+is interpreted as a contact, and the value -1 denotes an unused slot.  A
+tracking id not previously present is considered new, and a tracking id no
+longer present is considered removed.  Since only changes are propagated,
+the full state of each initiated contact has to reside in the receiving
+end.  Upon receiving an MT event, one simply updates the appropriate
+attribute of the current slot.
+
+
+Protocol Example A
+------------------
+
+Here is what a minimal event sequence for a two-contact touch would look
+like for a type A device:
+
+   ABS_MT_POSITION_X x[0]
+   ABS_MT_POSITION_Y y[0]
+   SYN_MT_REPORT
+   ABS_MT_POSITION_X x[1]
+   ABS_MT_POSITION_Y y[1]
+   SYN_MT_REPORT
+   SYN_REPORT
 
+The sequence after moving one of the contacts looks exactly the same; the
+raw data for all present contacts are sent between every synchronization
+with SYN_REPORT.
 
-Usage
------
+Here is the sequence after lifting the first contact:
+
+   ABS_MT_POSITION_X x[1]
+   ABS_MT_POSITION_Y y[1]
+   SYN_MT_REPORT
+   SYN_REPORT
+
+And here is the sequence after lifting the second contact:
+
+   SYN_MT_REPORT
+   SYN_REPORT
+
+If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
+ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
+last SYN_REPORT will be dropped by the input core, resulting in no
+zero-contact event reaching userland.
 
-Anonymous finger details are sent sequentially as separate packets of ABS
-events. Only the ABS_MT events are recognized as part of a finger
-packet. The end of a packet is marked by calling the input_mt_sync()
-function, which generates a SYN_MT_REPORT event. This instructs the
-receiver to accept the data for the current finger and prepare to receive
-another. The end of a multi-touch transfer is marked by calling the usual
-input_sync() function. This instructs the receiver to act upon events
-accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new
-set of events/packets.
+
+Protocol Example B
+------------------
+
+Here is what a minimal event sequence for a two-contact touch would look
+like for a type B device:
+
+   ABS_MT_SLOT 0
+   ABS_MT_TRACKING_ID 45
+   ABS_MT_POSITION_X x[0]
+   ABS_MT_POSITION_Y y[0]
+   ABS_MT_SLOT 1
+   ABS_MT_TRACKING_ID 46
+   ABS_MT_POSITION_X x[1]
+   ABS_MT_POSITION_Y y[1]
+   SYN_REPORT
+
+Here is the sequence after moving contact 45 in the x direction:
+
+   ABS_MT_SLOT 0
+   ABS_MT_POSITION_X x[0]
+   SYN_REPORT
+
+Here is the sequence after lifting the contact in slot 0:
+
+   ABS_MT_TRACKING_ID -1
+   SYN_REPORT
+
+The slot being modified is already 0, so the ABS_MT_SLOT is omitted.  The
+message removes the association of slot 0 with contact 45, thereby
+destroying contact 45 and freeing slot 0 to be reused for another contact.
+
+Finally, here is the sequence after lifting the second contact:
+
+   ABS_MT_SLOT 1
+   ABS_MT_TRACKING_ID -1
+   SYN_REPORT
+
+
+Event Usage
+-----------
 
 A set of ABS_MT events with the desired properties is defined. The events
 are divided into categories, to allow for partial implementation.  The
 minimum set consists of ABS_MT_POSITION_X and ABS_MT_POSITION_Y, which
-allows for multiple fingers to be tracked.  If the device supports it, the
+allows for multiple contacts to be tracked.  If the device supports it, the
 ABS_MT_TOUCH_MAJOR and ABS_MT_WIDTH_MAJOR may be used to provide the size
-of the contact area and approaching finger, respectively.
+of the contact area and approaching contact, respectively.
 
 The TOUCH and WIDTH parameters have a geometrical interpretation; imagine
 looking through a window at someone gently holding a finger against the
@@ -41,56 +159,26 @@ ABS_MT_TOUCH_MAJOR, the diameter of the outer region is
 ABS_MT_WIDTH_MAJOR. Now imagine the person pressing the finger harder
 against the glass. The inner region will increase, and in general, the
 ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
-unity, is related to the finger pressure. For pressure-based devices,
+unity, is related to the contact pressure. For pressure-based devices,
 ABS_MT_PRESSURE may be used to provide the pressure on the contact area
 instead.
 
-In addition to the MAJOR parameters, the oval shape of the finger can be
+In addition to the MAJOR parameters, the oval shape of the contact can be
 described by adding the MINOR parameters, such that MAJOR and MINOR are the
 major and minor axis of an ellipse. Finally, the orientation of the oval
 shape can be describe with the ORIENTATION parameter.
 
 The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
-finger or a pen or something else.  Devices with more granular information
+contact or a pen or something else.  Devices with more granular information
 may specify general shapes as blobs, i.e., as a sequence of rectangular
 shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
 that currently support it, the ABS_MT_TRACKING_ID event may be used to
-report finger tracking from hardware [5].
+report contact tracking from hardware [5].
 
-Here is what a minimal event sequence for a two-finger touch would look
-like:
-
-   ABS_MT_POSITION_X
-   ABS_MT_POSITION_Y
-   SYN_MT_REPORT
-   ABS_MT_POSITION_X
-   ABS_MT_POSITION_Y
-   SYN_MT_REPORT
-   SYN_REPORT
-
-Here is the sequence after lifting one of the fingers:
-
-   ABS_MT_POSITION_X
-   ABS_MT_POSITION_Y
-   SYN_MT_REPORT
-   SYN_REPORT
-
-And here is the sequence after lifting the remaining finger:
-
-   SYN_MT_REPORT
-   SYN_REPORT
-
-If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
-ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
-last SYN_REPORT will be dropped by the input core, resulting in no
-zero-finger event reaching userland.
 
 Event Semantics
 ---------------
 
-The word "contact" is used to describe a tool which is in direct contact
-with the surface. A finger, a pen or a rubber all classify as contacts.
-
 ABS_MT_TOUCH_MAJOR
 
 The length of the major axis of the contact. The length should be given in
@@ -157,15 +245,16 @@ MT_TOOL_PEN [2].
 ABS_MT_BLOB_ID
 
 The BLOB_ID groups several packets together into one arbitrarily shaped
-contact. This is a low-level anonymous grouping, and should not be confused
-with the high-level trackingID [5]. Most kernel drivers will not have blob
-capability, and can safely omit the event.
+contact. This is a low-level anonymous grouping for type A devices, and
+should not be confused with the high-level trackingID [5]. Most type A
+devices do not have blob capability, so drivers can safely omit this event.
 
 ABS_MT_TRACKING_ID
 
 The TRACKING_ID identifies an initiated contact throughout its life cycle
-[5]. There are currently only a few devices that support it, so this event
-should normally be omitted.
+[5]. This event is mandatory for type B devices. The value range of the
+TRACKING_ID should be large enough to ensure unique identification of a
+contact maintained over an extended period of time.
 
 
 Event Computation
@@ -192,20 +281,11 @@ finger along the X axis (1).
 Finger Tracking
 ---------------
 
-The kernel driver should generate an arbitrary enumeration of the set of
-anonymous contacts currently on the surface. The order in which the packets
-appear in the event stream is not important.
-
 The process of finger tracking, i.e., to assign a unique trackingID to each
-initiated contact on the surface, is left to user space; preferably the
-multi-touch X driver [3]. In that driver, the trackingID stays the same and
-unique until the contact vanishes (when the finger leaves the surface). The
-problem of assigning a set of anonymous fingers to a set of identified
-fingers is a euclidian bipartite matching problem at each event update, and
-relies on a sufficiently rapid update rate.
-
-There are a few devices that support trackingID in hardware. User space can
-make use of these native identifiers to reduce bandwidth and cpu usage.
+initiated contact on the surface, is a Euclidian Bipartite Matching
+problem.  At each event synchronization, the set of actual contacts is
+matched to the set of contacts from the previous synchronization. A full
+implementation can be found in [3].
 
 
 Gestures
index 2b2407d9a6d025a8451605b104a35daa7da59b47..b61f89fa01c193def3bc453f2422c4cc40ac06bb 100644 (file)
@@ -93,6 +93,7 @@ parameter is applicable:
                        Documentation/scsi/.
        SECURITY Different security models are enabled.
        SELINUX SELinux support is enabled.
+       APPARMOR AppArmor support is enabled.
        SERIAL  Serial support is enabled.
        SH      SuperH architecture is enabled.
        SMP     The kernel is an SMP kernel.
@@ -2312,6 +2313,13 @@ and is between 256 and 4096 characters. It is defined in the file
                        If enabled at boot time, /selinux/disable can be used
                        later to disable prior to initial policy load.
 
+       apparmor=       [APPARMOR] Disable or enable AppArmor at boot time
+                       Format: { "0" | "1" }
+                       See security/apparmor/Kconfig help text
+                       0 -- disable.
+                       1 -- enable.
+                       Default value is set via kernel config option.
+
        serialnumber    [BUGS=X86-32]
 
        shapers=        [NET]
index b3a232cae7f8d2bf41683cc32f15840b87467335..200a2d37cbc8970e08ac3f2c2323ba066c4f3bdb 100644 (file)
@@ -3,8 +3,8 @@
 TOMOYO is a name-based MAC extension (LSM module) for the Linux kernel.
 
 LiveCD-based tutorials are available at
-http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/ubuntu8.04-live/
-http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/centos5-live/ .
+http://tomoyo.sourceforge.jp/1.7/1st-step/ubuntu10.04-live/
+http://tomoyo.sourceforge.jp/1.7/1st-step/centos5-live/ .
 Though these tutorials use non-LSM version of TOMOYO, they are useful for you
 to know what TOMOYO is.
 
@@ -13,12 +13,12 @@ to know what TOMOYO is.
 Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" on
 kernel's command line.
 
-Please see http://tomoyo.sourceforge.jp/en/2.2.x/ for details.
+Please see http://tomoyo.sourceforge.jp/2.3/ for details.
 
 --- Where is documentation? ---
 
 User <-> Kernel interface documentation is available at
-http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html .
+http://tomoyo.sourceforge.jp/2.3/policy-reference.html .
 
 Materials we prepared for seminars and symposiums are available at
 http://sourceforge.jp/projects/tomoyo/docs/?category_id=532&language_id=1 .
@@ -50,6 +50,6 @@ multiple LSM modules at the same time. We feel sorry that you have to give up
 SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
 
 We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
-version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
+version of TOMOYO, available at http://tomoyo.sourceforge.jp/1.7/ .
 LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
 to port non-LSM version's functionalities to LSM versions.
index 16ca030e11856d93f246e86c8812784aff6837d9..87c46347bd6362f0f20927646387cb05444536e3 100644 (file)
@@ -17,9 +17,9 @@
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
  17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
  18 -> Hauppauge WinTV-HVR1270                             [0070:2211]
- 19 -> Hauppauge WinTV-HVR1275                             [0070:2215]
- 20 -> Hauppauge WinTV-HVR1255                             [0070:2251]
- 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295]
+ 19 -> Hauppauge WinTV-HVR1275                             [0070:2215,0070:221d,0070:22f2]
+ 20 -> Hauppauge WinTV-HVR1255                             [0070:2251,0070:2259,0070:22f1]
+ 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295,0070:2299,0070:229d,0070:22f0,0070:22f3,0070:22f4,0070:22f5]
  22 -> Mygica X8506 DMB-TH                                 [14f1:8651]
  23 -> Magic-Pro ProHDTV Extreme 2                         [14f1:8657]
  24 -> Hauppauge WinTV-HVR1850                             [0070:8541]
index 3a623aaeae5fa4df73900bce4223d3960dcfaa95..5c568757c3012fa6765efe42019304ca33eef413 100644 (file)
@@ -72,3 +72,4 @@
  73 -> Reddo DVB-C USB TV Box                   (em2870)
  74 -> Actionmaster/LinXcel/Digitus VC211A      (em2800)
  75 -> Dikom DK300                              (em2882)
+ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
index 1387a69ae3aa5f4842ea522bb5ec4b09a568e41a..4000c29fcfb6b602d0391eaffbd174124cdbeb97 100644 (file)
 177 -> Hawell HW-404M7
 178 -> Beholder BeholdTV H7                     [5ace:7190]
 179 -> Beholder BeholdTV A7                     [5ace:7090]
-180 -> Avermedia M733A                          [1461:4155,1461:4255]
+180 -> Avermedia PCI M733A                      [1461:4155,1461:4255]
+181 -> TechoTrend TT-budget T-3000              [13c2:2804]
index f13eb036c439a4af60310fff845a4e3b82552fa5..56ba7bba716888c7b16878bceff54d8df8691e22 100644 (file)
@@ -29,8 +29,12 @@ zc3xx                041e:4029       Creative WebCam Vista Pro
 zc3xx          041e:4034       Creative Instant P0620
 zc3xx          041e:4035       Creative Instant P0620D
 zc3xx          041e:4036       Creative Live !
+sq930x         041e:4038       Creative Joy-IT
 zc3xx          041e:403a       Creative Nx Pro 2
 spca561                041e:403b       Creative Webcam Vista (VF0010)
+sq930x         041e:403c       Creative Live! Ultra
+sq930x         041e:403d       Creative Live! Ultra for Notebooks
+sq930x         041e:4041       Creative Live! Motion
 zc3xx          041e:4051       Creative Live!Cam Notebook Pro (VF0250)
 ov519          041e:4052       Creative Live! VISTA IM
 zc3xx          041e:4053       Creative Live!Cam Video IM
@@ -138,6 +142,7 @@ finepix             04cb:013d       Fujifilm FinePix unknown model
 finepix                04cb:013f       Fujifilm FinePix F420
 sunplus                04f1:1001       JVC GC A50
 spca561                04fc:0561       Flexcam 100
+spca1528       04fc:1528       Sunplus MD80 clone
 sunplus                04fc:500c       Sunplus CA500C
 sunplus                04fc:504a       Aiptek Mini PenCam 1.3
 sunplus                04fc:504b       Maxell MaxPocket LE 1.3
@@ -253,6 +258,7 @@ pac7302             093a:2620       Apollo AC-905
 pac7302                093a:2621       PAC731x
 pac7302                093a:2622       Genius Eye 312
 pac7302                093a:2624       PAC7302
+pac7302                093a:2625       Genius iSlim 310
 pac7302                093a:2626       Labtec 2200
 pac7302                093a:2628       Genius iLook 300
 pac7302                093a:2629       Genious iSlim 300
@@ -362,6 +368,8 @@ sq905c              2770:9052       Disney pix micro 2 (VGA)
 sq905c         2770:905c       All 11 known cameras with this ID
 sq905          2770:9120       All 24 known cameras with this ID
 sq905c         2770:913d       All 4 known cameras with this ID
+sq930x         2770:930b       Sweex Motion Tracking / I-Tec iCam Tracer
+sq930x         2770:930c       Trust WB-3500T / NSG Robbie 2.0
 spca500                2899:012c       Toptro Industrial
 ov519          8020:ef04       ov519
 spca508                8086:0110       Intel Easy PC Camera
index db3d0f5061f9c42e301e420878b0dc5cbe31e6e1..33606bb91f1f77e27906475a7725c0f9df02e2ac 100644 (file)
@@ -5061,6 +5061,14 @@ S:       Supported
 F:     include/linux/selinux*
 F:     security/selinux/
 
+APPARMOR SECURITY MODULE
+M:     John Johansen <john.johansen@canonical.com>
+L:     apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+W:     apparmor.wiki.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
+S:     Supported
+F:     security/apparmor/
+
 SENSABLE PHANTOM
 M:     Jiri Slaby <jirislaby@gmail.com>
 S:     Maintained
@@ -5605,7 +5613,7 @@ L:        tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and us
 L:     tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
 L:     tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
 W:     http://tomoyo.sourceforge.jp/
-T:     quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
+T:     quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.3.x/tomoyo-lsm/patches/
 S:     Maintained
 F:     security/tomoyo/
 
@@ -6243,6 +6251,8 @@ F:        drivers/mmc/host/wbsd.*
 
 WATCHDOG DEVICE DRIVERS
 M:     Wim Van Sebroeck <wim@iguana.be>
+L:     linux-watchdog@vger.kernel.org
+W:     http://www.linux-watchdog.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog.git
 S:     Maintained
 F:     Documentation/watchdog/
index 886bf04931d4aea56c26761b26898a8f393fb9ce..141da26fda4b87870ba19237f61ced915d0cebcb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 35
-EXTRAVERSION = -rc6
+EXTRAVERSION =
 NAME = Sheep on Meth
 
 # *DOCUMENTATION*
index 98922f7d2d1236dd7fd29fa404447b46189c0222..e39caa8b0c93e323c9c1e2feda7bb90fd1a3a4a1 100644 (file)
@@ -10,6 +10,7 @@ config ARM
        default y
        select HAVE_AOUT
        select HAVE_IDE
+       select HAVE_MEMBLOCK
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
        select GENERIC_ATOMIC64 if (!CPU_32v6K)
@@ -24,6 +25,7 @@ config ARM
        select HAVE_KERNEL_LZMA
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
+       select HAVE_REGS_AND_STACK_ACCESS_API
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
@@ -55,7 +57,7 @@ config GENERIC_CLOCKEVENTS
 config GENERIC_CLOCKEVENTS_BROADCAST
        bool
        depends on GENERIC_CLOCKEVENTS
-       default y if SMP && !LOCAL_TIMERS
+       default y if SMP
 
 config HAVE_TCM
        bool
@@ -301,6 +303,7 @@ config ARCH_CNS3XXX
        select CPU_V6
        select GENERIC_CLOCKEVENTS
        select ARM_GIC
+       select PCI_DOMAINS if PCI
        help
          Support for Cavium Networks CNS3XXX platform.
 
@@ -439,21 +442,6 @@ config ARCH_IXP4XX
        help
          Support for Intel's IXP4XX (XScale) family of processors.
 
-config ARCH_L7200
-       bool "LinkUp-L7200"
-       select CPU_ARM720T
-       select FIQ
-       select ARCH_USES_GETTIMEOFFSET
-       help
-         Say Y here if you intend to run this kernel on a LinkUp Systems
-         L7200 Software Development Board which uses an ARM720T processor.
-         Information on this board can be obtained at:
-
-         <http://www.linkupsys.com/>
-
-         If you have any questions or comments about the Linux kernel port
-         to this board, send e-mail to <sjhill@cotw.com>.
-
 config ARCH_DOVE
        bool "Marvell Dove"
        select PCI
@@ -482,6 +470,19 @@ config ARCH_LOKI
        help
          Support for the Marvell Loki (88RC8480) SoC.
 
+config ARCH_LPC32XX
+       bool "NXP LPC32XX"
+       select CPU_ARM926T
+       select ARCH_REQUIRE_GPIOLIB
+       select HAVE_IDE
+       select ARM_AMBA
+       select USB_ARCH_HAS_OHCI
+       select COMMON_CLKDEV
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       help
+         Support for the NXP LPC32XX family of processors
+
 config ARCH_MV78XX0
        bool "Marvell MV78xx0"
        select CPU_FEROCEON
@@ -586,6 +587,7 @@ config ARCH_MSM
        bool "Qualcomm MSM"
        select HAVE_CLK
        select GENERIC_CLOCKEVENTS
+       select ARCH_REQUIRE_GPIOLIB
        help
          Support for Qualcomm MSM/QSD based systems.  This runs on the
          apps processor of the MSM/QSD and depends on a shared memory
@@ -719,7 +721,6 @@ config ARCH_SHARK
 config ARCH_LH7A40X
        bool "Sharp LH7A40X"
        select CPU_ARM922T
-       select ARCH_DISCONTIGMEM_ENABLE if !LH7A40X_CONTIGMEM
        select ARCH_SPARSEMEM_ENABLE if !LH7A40X_CONTIGMEM
        select ARCH_USES_GETTIMEOFFSET
        help
@@ -845,6 +846,8 @@ source "arch/arm/mach-lh7a40x/Kconfig"
 
 source "arch/arm/mach-loki/Kconfig"
 
+source "arch/arm/mach-lpc32xx/Kconfig"
+
 source "arch/arm/mach-msm/Kconfig"
 
 source "arch/arm/mach-mv78xx0/Kconfig"
@@ -1031,11 +1034,6 @@ endmenu
 
 source "arch/arm/common/Kconfig"
 
-config FORCE_MAX_ZONEORDER
-       int
-       depends on SA1111
-       default "9"
-
 menu "Bus support"
 
 config ARM_AMBA
@@ -1060,7 +1058,7 @@ config ISA_DMA_API
        bool
 
 config PCI
-       bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695 || MACH_ARMCORE
+       bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695 || MACH_ARMCORE || ARCH_CNS3XXX
        help
          Find out whether you have a PCI motherboard. PCI is the name of a
          bus system, i.e. the way the CPU talks to the other stuff inside
@@ -1172,9 +1170,10 @@ config HOTPLUG_CPU
 config LOCAL_TIMERS
        bool "Use local timer interrupts"
        depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \
-               REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || ARCH_U8500)
+               REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
+               ARCH_U8500 || ARCH_VEXPRESS_CA9X4)
        default y
-       select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_OMAP4 || ARCH_U8500)
+       select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_OMAP4 || ARCH_U8500)
        help
          Enable support for local timers on SMP platforms, rather then the
          legacy IPI broadcast method.  Local timers allows the system
@@ -1185,10 +1184,10 @@ source kernel/Kconfig.preempt
 
 config HZ
        int
-       default 128 if ARCH_L7200
        default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PV210
        default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
        default AT91_TIMER_HZ if ARCH_AT91
+       default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
        default 100
 
 config THUMB2_KERNEL
@@ -1241,10 +1240,6 @@ config OABI_COMPAT
 config ARCH_HAS_HOLES_MEMORYMODEL
        bool
 
-# Discontigmem is deprecated
-config ARCH_DISCONTIGMEM_ENABLE
-       bool
-
 config ARCH_SPARSEMEM_ENABLE
        bool
 
@@ -1252,13 +1247,7 @@ config ARCH_SPARSEMEM_DEFAULT
        def_bool ARCH_SPARSEMEM_ENABLE
 
 config ARCH_SELECT_MEMORY_MODEL
-       def_bool ARCH_DISCONTIGMEM_ENABLE && ARCH_SPARSEMEM_ENABLE
-
-config NODES_SHIFT
-       int
-       default "4" if ARCH_LH7A40X
-       default "2"
-       depends on NEED_MULTIPLE_NODES
+       def_bool ARCH_SPARSEMEM_ENABLE
 
 config HIGHMEM
        bool "High Memory Support (EXPERIMENTAL)"
@@ -1290,8 +1279,33 @@ config HW_PERF_EVENTS
          Enable hardware performance counter support for perf events. If
          disabled, perf events will use software events only.
 
+config SPARSE_IRQ
+       def_bool n
+       help
+         This enables support for sparse irqs. This is useful in general
+         as most CPUs have a fairly sparse array of IRQ vectors, which
+         the irq_desc then maps directly on to. Systems with a high
+         number of off-chip IRQs will want to treat this as
+         experimental until they have been independently verified.
+
 source "mm/Kconfig"
 
+config FORCE_MAX_ZONEORDER
+       int "Maximum zone order" if ARCH_SHMOBILE
+       range 11 64 if ARCH_SHMOBILE
+       default "9" if SA1111
+       default "11"
+       help
+         The kernel memory allocator divides physically contiguous memory
+         blocks into "zones", where each zone is a power of two number of
+         pages.  This option selects the largest power of two that the kernel
+         keeps in the memory allocator.  If you need to allocate very large
+         blocks of physically contiguous memory, then you may need to
+         increase this value.
+
+         This config option is actually maximum order plus one. For example,
+         a value of 11 means that the largest free memory block is 2^10 pages.
+
 config LEDS
        bool "Timer and CPU usage LEDs"
        depends on ARCH_CDB89712 || ARCH_EBSA110 || \
@@ -1375,6 +1389,24 @@ config UACCESS_WITH_MEMCPY
          However, if the CPU data cache is using a write-allocate mode,
          this option is unlikely to provide any performance gain.
 
+config CC_STACKPROTECTOR
+       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+       help
+         This option turns on the -fstack-protector GCC feature. This
+         feature puts, at the beginning of functions, a canary value on
+         the stack just before the return address, and validates
+         the value just before actually returning.  Stack based buffer
+         overflows (that need to overwrite this return address) now also
+         overwrite the canary, which gets detected and the attack is then
+         neutralized via a kernel panic.
+         This feature requires gcc version 4.2 or above.
+
+config DEPRECATED_PARAM_STRUCT
+       bool "Provide old way to pass kernel parameters"
+       help
+         This was deprecated in 2001 and announced to live on for 5 years.
+         Some old boot loaders still use this way.
+
 endmenu
 
 menu "Boot options"
@@ -1485,6 +1517,105 @@ config ATAGS_PROC
          Should the atags used to boot the kernel be exported in an "atags"
          file in procfs. Useful with kexec.
 
+config AUTO_ZRELADDR
+       bool "Auto calculation of the decompressed kernel image address"
+       depends on !ZBOOT_ROM && !ARCH_U300
+       help
+         ZRELADDR is the physical address where the decompressed kernel
+         image will be placed. If AUTO_ZRELADDR is selected, the address
+         will be determined at run-time by masking the current IP with
+         0xf8000000. This assumes the zImage being placed in the first 128MB
+         from start of memory.
+
+config ZRELADDR
+       hex "Physical address of the decompressed kernel image"
+       depends on !AUTO_ZRELADDR
+       default 0x00008000 if ARCH_BCMRING ||\
+               ARCH_CNS3XXX ||\
+               ARCH_DOVE ||\
+               ARCH_EBSA110 ||\
+               ARCH_FOOTBRIDGE ||\
+               ARCH_INTEGRATOR ||\
+               ARCH_IOP13XX ||\
+               ARCH_IOP33X ||\
+               ARCH_IXP2000 ||\
+               ARCH_IXP23XX ||\
+               ARCH_IXP4XX ||\
+               ARCH_KIRKWOOD ||\
+               ARCH_KS8695 ||\
+               ARCH_LOKI ||\
+               ARCH_MMP ||\
+               ARCH_MV78XX0 ||\
+               ARCH_NOMADIK ||\
+               ARCH_NUC93X ||\
+               ARCH_NS9XXX ||\
+               ARCH_ORION5X ||\
+               ARCH_SPEAR3XX ||\
+               ARCH_SPEAR6XX ||\
+               ARCH_U8500 ||\
+               ARCH_VERSATILE ||\
+               ARCH_W90X900
+       default 0x08008000 if ARCH_MX1 ||\
+               ARCH_SHARK
+       default 0x10008000 if ARCH_MSM ||\
+               ARCH_OMAP1 ||\
+               ARCH_RPC
+       default 0x20008000 if ARCH_S5P6440 ||\
+               ARCH_S5P6442 ||\
+               ARCH_S5PC100 ||\
+               ARCH_S5PV210
+       default 0x30008000 if ARCH_S3C2410 ||\
+               ARCH_S3C2400 ||\
+               ARCH_S3C2412 ||\
+               ARCH_S3C2416 ||\
+               ARCH_S3C2440 ||\
+               ARCH_S3C2443
+       default 0x40008000 if ARCH_STMP378X ||\
+               ARCH_STMP37XX ||\
+               ARCH_SH7372 ||\
+               ARCH_SH7377
+       default 0x50008000 if ARCH_S3C64XX ||\
+               ARCH_SH7367
+       default 0x60008000 if ARCH_VEXPRESS
+       default 0x80008000 if ARCH_MX25 ||\
+               ARCH_MX3 ||\
+               ARCH_NETX ||\
+               ARCH_OMAP2PLUS ||\
+               ARCH_PNX4008
+       default 0x90008000 if ARCH_MX5 ||\
+               ARCH_MX91231
+       default 0xa0008000 if ARCH_IOP32X ||\
+               ARCH_PXA ||\
+               MACH_MX27
+       default 0xc0008000 if ARCH_LH7A40X ||\
+               MACH_MX21
+       default 0xf0008000 if ARCH_AAEC2000 ||\
+               ARCH_L7200
+       default 0xc0028000 if ARCH_CLPS711X
+       default 0x70008000 if ARCH_AT91 && (ARCH_AT91CAP9 || ARCH_AT91SAM9G45)
+       default 0x20008000 if ARCH_AT91 && !(ARCH_AT91CAP9 || ARCH_AT91SAM9G45)
+       default 0xc0008000 if ARCH_DAVINCI && ARCH_DAVINCI_DA8XX
+       default 0x80008000 if ARCH_DAVINCI && !ARCH_DAVINCI_DA8XX
+       default 0x00008000 if ARCH_EP93XX && EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       default 0xc0008000 if ARCH_EP93XX && EP93XX_SDCE0_PHYS_OFFSET
+       default 0xd0008000 if ARCH_EP93XX && EP93XX_SDCE1_PHYS_OFFSET
+       default 0xe0008000 if ARCH_EP93XX && EP93XX_SDCE2_PHYS_OFFSET
+       default 0xf0008000 if ARCH_EP93XX && EP93XX_SDCE3_ASYNC_PHYS_OFFSET
+       default 0x00008000 if ARCH_GEMINI && GEMINI_MEM_SWAP
+       default 0x10008000 if ARCH_GEMINI && !GEMINI_MEM_SWAP
+       default 0x70008000 if ARCH_REALVIEW && REALVIEW_HIGH_PHYS_OFFSET
+       default 0x00008000 if ARCH_REALVIEW && !REALVIEW_HIGH_PHYS_OFFSET
+       default 0xc0208000 if ARCH_SA1100 && SA1111
+       default 0xc0008000 if ARCH_SA1100 && !SA1111
+       default 0x30108000 if ARCH_S3C2410 && PM_H1940
+       default 0x28E08000 if ARCH_U300 && MACH_U300_SINGLE_RAM
+       default 0x48008000 if ARCH_U300 && !MACH_U300_SINGLE_RAM
+       help
+         ZRELADDR is the physical address where the decompressed kernel
+         image will be placed. ZRELADDR has to be specified when the
+         assumption of AUTO_ZRELADDR is not valid, or when ZBOOT_ROM is
+         selected.
+
 endmenu
 
 menu "CPU Power Management"
index 64ba313724d2377fda7e439e130d7ad69dd1a83c..63d998e8c672ef4488eb72df2cfdcce2f7ae502f 100644 (file)
@@ -34,6 +34,10 @@ ifeq ($(CONFIG_FRAME_POINTER),y)
 KBUILD_CFLAGS  +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
 endif
 
+ifeq ($(CONFIG_CC_STACKPROTECTOR),y)
+KBUILD_CFLAGS  +=-fstack-protector
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
 KBUILD_CPPFLAGS        += -mbig-endian
 AS             += -EB
@@ -139,14 +143,14 @@ machine-$(CONFIG_ARCH_IXP23XX)            := ixp23xx
 machine-$(CONFIG_ARCH_IXP4XX)          := ixp4xx
 machine-$(CONFIG_ARCH_KIRKWOOD)                := kirkwood
 machine-$(CONFIG_ARCH_KS8695)          := ks8695
-machine-$(CONFIG_ARCH_L7200)           := l7200
 machine-$(CONFIG_ARCH_LH7A40X)         := lh7a40x
 machine-$(CONFIG_ARCH_LOKI)            := loki
+machine-$(CONFIG_ARCH_LPC32XX)         := lpc32xx
 machine-$(CONFIG_ARCH_MMP)             := mmp
 machine-$(CONFIG_ARCH_MSM)             := msm
 machine-$(CONFIG_ARCH_MV78XX0)         := mv78xx0
-machine-$(CONFIG_ARCH_MX1)             := mx1
-machine-$(CONFIG_ARCH_MX2)             := mx2
+machine-$(CONFIG_ARCH_MX1)             := imx
+machine-$(CONFIG_ARCH_MX2)             := imx
 machine-$(CONFIG_ARCH_MX25)            := mx25
 machine-$(CONFIG_ARCH_MX3)             := mx3
 machine-$(CONFIG_ARCH_MX5)             := mx5
index 4a590f4113e2af044ea1764aeb0681ad7f50a74c..f705213caa881af9c07e181c0d2a3a1a26a5d98a 100644 (file)
 MKIMAGE         := $(srctree)/scripts/mkuboot.sh
 
 ifneq ($(MACHINE),)
-include $(srctree)/$(MACHINE)/Makefile.boot
+-include $(srctree)/$(MACHINE)/Makefile.boot
 endif
 
 # Note: the following conditions must always be true:
-#   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
 #   PARAMS_PHYS must be within 4MB of ZRELADDR
 #   INITRD_PHYS must be in RAM
-ZRELADDR    := $(zreladdr-y)
 PARAMS_PHYS := $(params_phys-y)
 INITRD_PHYS := $(initrd_phys-y)
 
-export ZRELADDR INITRD_PHYS PARAMS_PHYS
+export INITRD_PHYS PARAMS_PHYS
 
 targets := Image zImage xipImage bootpImage uImage
 
@@ -67,7 +65,7 @@ quiet_cmd_uimage = UIMAGE  $@
 ifeq ($(CONFIG_ZBOOT_ROM),y)
 $(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
 else
-$(obj)/uImage: LOADADDR=$(ZRELADDR)
+$(obj)/uImage: LOADADDR=$(CONFIG_ZRELADDR)
 endif
 
 ifeq ($(CONFIG_THUMB2_KERNEL),y)
index 53faa9063a035be790c3aef7c5f32c4f48eb8025..7636c9b3f9a7899f9209d9a82fa78de8a6dc9b17 100644 (file)
@@ -4,6 +4,7 @@
 # create a compressed vmlinuz image from the original vmlinux
 #
 
+AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
 HEAD   = head.o
 OBJS   = misc.o decompress.o
 FONTC  = $(srctree)/drivers/video/console/font_acorn_8x8.c
@@ -19,10 +20,6 @@ ifeq ($(CONFIG_ARCH_SHARK),y)
 OBJS           += head-shark.o ofw-shark.o
 endif
 
-ifeq ($(CONFIG_ARCH_L7200),y)
-OBJS           += head-l7200.o
-endif
-
 ifeq ($(CONFIG_ARCH_P720T),y)
 # Borrow this code from SA1100
 OBJS           += head-sa1100.o
@@ -71,6 +68,9 @@ targets       := vmlinux vmlinux.lds \
                 piggy.$(suffix_y) piggy.$(suffix_y).o \
                 font.o font.c head.o misc.o $(OBJS)
 
+# Make sure files are removed during clean
+extra-y       += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S
+
 ifeq ($(CONFIG_FUNCTION_TRACER),y)
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
@@ -79,19 +79,9 @@ endif
 EXTRA_CFLAGS  := -fpic -fno-builtin
 EXTRA_AFLAGS  := -Wa,-march=all
 
-# Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
-# linker symbols.  We only define initrd_phys and params_phys if the
-# machine class defined the corresponding makefile variable.
-LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR)
 ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux += --be8
 endif
-ifneq ($(INITRD_PHYS),)
-LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS)
-endif
-ifneq ($(PARAMS_PHYS),)
-LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS)
-endif
 # ?
 LDFLAGS_vmlinux += -p
 # Report unresolved symbol references
diff --git a/arch/arm/boot/compressed/Makefile.debug b/arch/arm/boot/compressed/Makefile.debug
deleted file mode 100644 (file)
index 491a037..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# linux/arch/arm/boot/compressed/Makefile
-#
-# create a compressed vmlinux image from the original vmlinux
-#
-
-COMPRESSED_EXTRA=../../lib/ll_char_wr.o
-OBJECTS=misc-debug.o ll_char_wr.aout.o
-
-CFLAGS=-D__KERNEL__ -O2 -DSTDC_HEADERS -DSTANDALONE_DEBUG -Wall -I../../../../include -c
-
-test-gzip: piggy.aout.o $(OBJECTS)
-       $(CC) -o $@ $(OBJECTS) piggy.aout.o
-
-misc-debug.o: misc.c
-       $(CC) $(CFLAGS) -o $@ misc.c
-
-piggy.aout.o: piggy.o
-       arm-linuxelf-objcopy --change-leading-char -I elf32-arm -O arm-aout32-linux piggy.o piggy.aout.o
-
-ll_char_wr.aout.o: $(COMPRESSED_EXTRA)
-       arm-linuxelf-objcopy --change-leading-char -I elf32-arm -O arm-aout32-linux $(COMPRESSED_EXTRA) ll_char_wr.aout.o
-
diff --git a/arch/arm/boot/compressed/head-l7200.S b/arch/arm/boot/compressed/head-l7200.S
deleted file mode 100644 (file)
index d0e3b20..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 
- * linux/arch/arm/boot/compressed/head-l7200.S
- * 
- * Copyright (C) 2000 Steve Hill <sjhill@cotw.com>
- * 
- * Some code borrowed from Nicolas Pitre's 'head-sa1100.S' file. This
- * is merged with head.S by the linker.
- */
-
-#include <asm/mach-types.h>
-
-#ifndef CONFIG_ARCH_L7200
-#error What am I doing here...
-#endif
-
-               .section        ".start", "ax"
-
-__L7200_start:
-               mov     r0, #0x00100000         @ FLASH address of initrd
-               mov     r2, #0xf1000000         @ RAM address of initrd
-               add     r3, r2, #0x00700000     @ Size of initrd 
-1:
-               ldmia   r0!, {r4, r5, r6, r7}
-               stmia   r2!, {r4, r5, r6, r7}
-               cmp     r2, r3
-               ble     1b
-
-               mov     r8, #0                  @ Zero it out
-               mov     r7, #MACH_TYPE_L7200    @ Set architecture ID
index c5191b1532e8284cbeac17cef819522863a90743..abf4d65acf6243de88d3a0df342afabce87436e2 100644 (file)
@@ -170,9 +170,16 @@ not_angel:
 
                .text
                adr     r0, LC0
- ARM(          ldmia   r0, {r1, r2, r3, r4, r5, r6, r11, ip, sp})
- THUMB(                ldmia   r0, {r1, r2, r3, r4, r5, r6, r11, ip}   )
+ ARM(          ldmia   r0, {r1, r2, r3, r5, r6, r11, ip, sp})
+ THUMB(                ldmia   r0, {r1, r2, r3, r5, r6, r11, ip}       )
  THUMB(                ldr     sp, [r0, #32]                           )
+#ifdef CONFIG_AUTO_ZRELADDR
+               @ determine final kernel image address
+               and     r4, pc, #0xf8000000
+               add     r4, r4, #TEXT_OFFSET
+#else
+               ldr     r4, =CONFIG_ZRELADDR
+#endif
                subs    r0, r0, r1              @ calculate the delta offset
 
                                                @ if delta is zero, we are
@@ -310,18 +317,17 @@ wont_overwrite:   mov     r0, r4
 LC0:           .word   LC0                     @ r1
                .word   __bss_start             @ r2
                .word   _end                    @ r3
-               .word   zreladdr                @ r4
                .word   _start                  @ r5
                .word   _image_size             @ r6
                .word   _got_start              @ r11
                .word   _got_end                @ ip
-               .word   user_stack+4096         @ sp
+               .word   user_stack_end          @ sp
 LC1:           .word   reloc_end - reloc_start
                .size   LC0, . - LC0
 
 #ifdef CONFIG_ARCH_RPC
                .globl  params
-params:                ldr     r0, =params_phys
+params:                ldr     r0, =0x10000100         @ params_phys for RPC
                mov     pc, lr
                .ltorg
                .align
@@ -339,9 +345,8 @@ params:             ldr     r0, =params_phys
  *  r4 = kernel execution address
  *  r7 = architecture number
  *  r8 = atags pointer
- *  r9 = run-time address of "start"  (???)
  * On exit,
- *  r1, r2, r3, r9, r10, r12 corrupted
+ *  r0, r1, r2, r3, r9, r10, r12 corrupted
  * This routine must preserve:
  *  r4, r5, r6, r7, r8
  */
@@ -396,12 +401,18 @@ __armv3_mpu_cache_on:
 
                mov     r0, #0
                mcr     p15, 0, r0, c7, c0, 0   @ invalidate whole cache v3
+               /*
+                * ?? ARMv3 MMU does not allow reading the control register,
+                * does this really work on ARMv3 MPU?
+                */
                mrc     p15, 0, r0, c1, c0, 0   @ read control reg
                                                @ .... .... .... WC.M
                orr     r0, r0, #0x000d         @ .... .... .... 11.1
+               /* ?? this overwrites the value constructed above? */
                mov     r0, #0
                mcr     p15, 0, r0, c1, c0, 0   @ write control reg
 
+               /* ?? invalidate for the second time? */
                mcr     p15, 0, r0, c7, c0, 0   @ invalidate whole cache v3
                mov     pc, lr
 
@@ -771,8 +782,10 @@ proc_types:
  * Turn off the Cache and MMU.  ARMv3 does not support
  * reading the control register, but ARMv4 does.
  *
- * On exit, r0, r1, r2, r3, r9, r12 corrupted
- * This routine must preserve: r4, r6, r7
+ * On exit,
+ *  r0, r1, r2, r3, r9, r12 corrupted
+ * This routine must preserve:
+ *  r4, r6, r7
  */
                .align  5
 cache_off:     mov     r3, #12                 @ cache_off function
@@ -845,7 +858,7 @@ __armv3_mmu_cache_off:
  * Clean and flush the cache to maintain consistency.
  *
  * On exit,
- *  r1, r2, r3, r9, r11, r12 corrupted
+ *  r1, r2, r3, r9, r10, r11, r12 corrupted
  * This routine must preserve:
  *  r0, r4, r5, r6, r7
  */
@@ -988,7 +1001,7 @@ no_cache_id:
 __armv3_mmu_cache_flush:
 __armv3_mpu_cache_flush:
                mov     r1, #0
-               mcr     p15, 0, r0, c7, c0, 0   @ invalidate whole cache v3
+               mcr     p15, 0, r1, c7, c0, 0   @ invalidate whole cache v3
                mov     pc, lr
 
 /*
@@ -1001,6 +1014,7 @@ __armv3_mpu_cache_flush:
 phexbuf:       .space  12
                .size   phexbuf, . - phexbuf
 
+@ phex corrupts {r0, r1, r2, r3}
 phex:          adr     r3, phexbuf
                mov     r2, #0
                strb    r2, [r3, r1]
@@ -1015,6 +1029,7 @@ phex:             adr     r3, phexbuf
                strb    r2, [r3, r1]
                b       1b
 
+@ puts corrupts {r0, r1, r2, r3}
 puts:          loadsp  r3, r1
 1:             ldrb    r2, [r0], #1
                teq     r2, #0
@@ -1029,12 +1044,14 @@ puts:           loadsp  r3, r1
                teq     r0, #0
                bne     1b
                mov     pc, lr
+@ putc corrupts {r0, r1, r2, r3}
 putc:
                mov     r2, r0
                mov     r0, #0
                loadsp  r3, r1
                b       2b
 
+@ memdump corrupts {r0, r1, r2, r3, r10, r11, r12, lr}
 memdump:       mov     r12, r0
                mov     r10, lr
                mov     r11, #0
@@ -1070,3 +1087,4 @@ reloc_end:
                .align
                .section ".stack", "w"
 user_stack:    .space  4096
+user_stack_end:
index d2b2ef41cd4ff7ac32bf91e4e947cc57993cbb2d..e653a6d3c8d90dae62ee3da745bfce67c34d27fb 100644 (file)
@@ -28,9 +28,6 @@ unsigned int __machine_arch_type;
 
 #include <asm/unaligned.h>
 
-#ifdef STANDALONE_DEBUG
-#define putstr printf
-#else
 
 static void putstr(const char *ptr);
 extern void error(char *x);
@@ -116,7 +113,6 @@ static void putstr(const char *ptr)
        flush();
 }
 
-#endif
 
 void *memcpy(void *__dest, __const void *__src, size_t __n)
 {
@@ -186,7 +182,6 @@ asmlinkage void __div0(void)
 
 extern void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
 
-#ifndef STANDALONE_DEBUG
 
 unsigned long
 decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
@@ -211,18 +206,3 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
        putstr(" done, booting the kernel.\n");
        return output_ptr;
 }
-#else
-
-char output_buffer[1500*1024];
-
-int main()
-{
-       output_data = output_buffer;
-
-       putstr("Uncompressing Linux...");
-       decompress(input_data, input_data_end - input_data,
-                       NULL, NULL, output_data, NULL, error);
-       putstr("done.\n");
-       return 0;
-}
-#endif
index 337741f734ac08d7f438e5d6240293adf3c5c366..7dfa9a85bc0c875b11567025f68e92bd768d7419 100644 (file)
@@ -108,6 +108,51 @@ static void gic_unmask_irq(unsigned int irq)
        spin_unlock(&irq_controller_lock);
 }
 
+static int gic_set_type(unsigned int irq, unsigned int type)
+{
+       void __iomem *base = gic_dist_base(irq);
+       unsigned int gicirq = gic_irq(irq);
+       u32 enablemask = 1 << (gicirq % 32);
+       u32 enableoff = (gicirq / 32) * 4;
+       u32 confmask = 0x2 << ((gicirq % 16) * 2);
+       u32 confoff = (gicirq / 16) * 4;
+       bool enabled = false;
+       u32 val;
+
+       /* Interrupt configuration for SGIs can't be changed */
+       if (gicirq < 16)
+               return -EINVAL;
+
+       if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+               return -EINVAL;
+
+       spin_lock(&irq_controller_lock);
+
+       val = readl(base + GIC_DIST_CONFIG + confoff);
+       if (type == IRQ_TYPE_LEVEL_HIGH)
+               val &= ~confmask;
+       else if (type == IRQ_TYPE_EDGE_RISING)
+               val |= confmask;
+
+       /*
+        * As recommended by the spec, disable the interrupt before changing
+        * the configuration
+        */
+       if (readl(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
+               writel(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
+               enabled = true;
+       }
+
+       writel(val, base + GIC_DIST_CONFIG + confoff);
+
+       if (enabled)
+               writel(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
+
+       spin_unlock(&irq_controller_lock);
+
+       return 0;
+}
+
 #ifdef CONFIG_SMP
 static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
 {
@@ -161,6 +206,7 @@ static struct irq_chip gic_chip = {
        .ack            = gic_ack_irq,
        .mask           = gic_mask_irq,
        .unmask         = gic_unmask_irq,
+       .set_type       = gic_set_type,
 #ifdef CONFIG_SMP
        .set_affinity   = gic_set_cpu,
 #endif
index 6f80665f477e70b0acad4d6ead228295446863c3..517d50ddbeb3153d102e426fc915405bae76012b 100644 (file)
@@ -185,13 +185,10 @@ static struct sa1111_dev_info sa1111_devices[] = {
        },
 };
 
-void __init sa1111_adjust_zones(int node, unsigned long *size, unsigned long *holes)
+void __init sa1111_adjust_zones(unsigned long *size, unsigned long *holes)
 {
        unsigned int sz = SZ_1M >> PAGE_SHIFT;
 
-       if (node != 0)
-               sz = 0;
-
        size[1] = size[0] - sz;
        size[0] = sz;
 }
@@ -1028,13 +1025,12 @@ static int sa1111_remove(struct platform_device *pdev)
        struct sa1111 *sachip = platform_get_drvdata(pdev);
 
        if (sachip) {
-               __sa1111_remove(sachip);
-               platform_set_drvdata(pdev, NULL);
-
 #ifdef CONFIG_PM
                kfree(sachip->saved_state);
                sachip->saved_state = NULL;
 #endif
+               __sa1111_remove(sachip);
+               platform_set_drvdata(pdev, NULL);
        }
 
        return 0;
index f2e3a9088df6d43880779071e30dff09f695f37d..ccc9c9959b82baf75d0faa04769a85e79ac23d51 100644 (file)
@@ -13,11 +13,19 @@ CONFIG_MACH_RD88F6192_NAS=y
 CONFIG_MACH_RD88F6281=y
 CONFIG_MACH_MV88F6281GTW_GE=y
 CONFIG_MACH_SHEEVAPLUG=y
+CONFIG_MACH_ESATA_SHEEVAPLUG=y
+CONFIG_MACH_GURUPLUG=y
 CONFIG_MACH_TS219=y
 CONFIG_MACH_TS41X=y
 CONFIG_MACH_OPENRD_BASE=y
 CONFIG_MACH_OPENRD_CLIENT=y
+CONFIG_MACH_OPENRD_ULTIMATE=y
 CONFIG_MACH_NETSPACE_V2=y
+CONFIG_MACH_INETSPACE_V2=y
+CONFIG_MACH_NETSPACE_MAX_V2=y
+CONFIG_MACH_NET2BIG_V2=y
+CONFIG_MACH_NET5BIG_V2=y
+CONFIG_MACH_T5325=y
 # CONFIG_CPU_FEROCEON_OLD_ID is not set
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/lusl7200_defconfig b/arch/arm/configs/lusl7200_defconfig
deleted file mode 100644 (file)
index 816fc42..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_HOTPLUG is not set
-CONFIG_MODULES=y
-CONFIG_ARCH_L7200=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_ZBOOT_ROM_TEXT=0x00010000
-CONFIG_ZBOOT_ROM_BSS=0xf03e0000
-CONFIG_ZBOOT_ROM=y
-CONFIG_CMDLINE="console=tty0 console=ttyLU1,115200 root=/dev/ram initrd=0xf1000000,0x005dac7b mem=32M"
-CONFIG_BINFMT_AOUT=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_INPUT is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_EXT2_FS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_CRC32 is not set
index 51662feb9f1dd03b8e1c8a3f7d208c063208aa89..6750b8e45a4914a59f6ef6cbbcb0cc84efe0ead0 100644 (file)
@@ -121,4 +121,8 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
 extern void elf_set_personality(const struct elf32_hdr *);
 #define SET_PERSONALITY(ex)    elf_set_personality(&(ex))
 
+struct mm_struct;
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
 #endif
index f7bd52b1c3654430351a5b7c5f2665e527979908..c1062c317103f706b9b2209fe8a5146c9ea4e7bf 100644 (file)
@@ -19,6 +19,7 @@
 #define HWCAP_NEON     4096
 #define HWCAP_VFPv3    8192
 #define HWCAP_VFPv3D16 16384
+#define HWCAP_TLS      32768
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 /*
index c980156f32638f8f031b93e730d0c2e8396aec40..1261b1f928d95a9ac1cf374148208415c4dc248d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/types.h>
 #include <asm/byteorder.h>
 #include <asm/memory.h>
+#include <asm/system.h>
 
 /*
  * ISA I/O bus memory addresses are 1:1 with the physical address.
@@ -179,25 +180,38 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
  * IO port primitives for more information.
  */
 #ifdef __mem_pci
-#define readb(c) ({ __u8  __v = __raw_readb(__mem_pci(c)); __v; })
-#define readw(c) ({ __u16 __v = le16_to_cpu((__force __le16) \
+#define readb_relaxed(c) ({ u8  __v = __raw_readb(__mem_pci(c)); __v; })
+#define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16) \
                                        __raw_readw(__mem_pci(c))); __v; })
-#define readl(c) ({ __u32 __v = le32_to_cpu((__force __le32) \
+#define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32) \
                                        __raw_readl(__mem_pci(c))); __v; })
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
+
+#define writeb_relaxed(v,c)    ((void)__raw_writeb(v,__mem_pci(c)))
+#define writew_relaxed(v,c)    ((void)__raw_writew((__force u16) \
+                                       cpu_to_le16(v),__mem_pci(c)))
+#define writel_relaxed(v,c)    ((void)__raw_writel((__force u32) \
+                                       cpu_to_le32(v),__mem_pci(c)))
+
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+#define __iormb()              rmb()
+#define __iowmb()              wmb()
+#else
+#define __iormb()              do { } while (0)
+#define __iowmb()              do { } while (0)
+#endif
+
+#define readb(c)               ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
+#define readw(c)               ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
+#define readl(c)               ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+
+#define writeb(v,c)            ({ __iowmb(); writeb_relaxed(v,c); })
+#define writew(v,c)            ({ __iowmb(); writew_relaxed(v,c); })
+#define writel(v,c)            ({ __iowmb(); writel_relaxed(v,c); })
 
 #define readsb(p,d,l)          __raw_readsb(__mem_pci(p),d,l)
 #define readsw(p,d,l)          __raw_readsw(__mem_pci(p),d,l)
 #define readsl(p,d,l)          __raw_readsl(__mem_pci(p),d,l)
 
-#define writeb(v,c)            __raw_writeb(v,__mem_pci(c))
-#define writew(v,c)            __raw_writew((__force __u16) \
-                                       cpu_to_le16(v),__mem_pci(c))
-#define writel(v,c)            __raw_writel((__force __u32) \
-                                       cpu_to_le32(v),__mem_pci(c))
-
 #define writesb(p,d,l)         __raw_writesb(__mem_pci(p),d,l)
 #define writesw(p,d,l)         __raw_writesw(__mem_pci(p),d,l)
 #define writesl(p,d,l)         __raw_writesl(__mem_pci(p),d,l)
@@ -244,13 +258,13 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
  * io{read,write}{8,16,32} macros
  */
 #ifndef ioread8
-#define ioread8(p)     ({ unsigned int __v = __raw_readb(p); __v; })
-#define ioread16(p)    ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __v; })
-#define ioread32(p)    ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __v; })
+#define ioread8(p)     ({ unsigned int __v = __raw_readb(p); __iormb(); __v; })
+#define ioread16(p)    ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32(p)    ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })
 
-#define iowrite8(v,p)  __raw_writeb(v, p)
-#define iowrite16(v,p) __raw_writew((__force __u16)cpu_to_le16(v), p)
-#define iowrite32(v,p) __raw_writel((__force __u32)cpu_to_le32(v), p)
+#define iowrite8(v,p)  ({ __iowmb(); (void)__raw_writeb(v, p); })
+#define iowrite16(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_le16(v), p); })
+#define iowrite32(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_le32(v), p); })
 
 #define ioread8_rep(p,d,c)     __raw_readsb(p,d,c)
 #define ioread16_rep(p,d,c)    __raw_readsw(p,d,c)
index 237282f7c762f3056b2ce76ab1a0e18d75a1499c..2721a5814cb93b56e0583722df184440c9497532 100644 (file)
@@ -7,6 +7,8 @@
 #define irq_canonicalize(i)    (i)
 #endif
 
+#define NR_IRQS_LEGACY 16
+
 /*
  * Use this value to indicate lack of interrupt
  * capability
index df15a0dc228e23da027667d3a992658daadf2305..8ec9ef5c3c7be25a2705451e8aab0a8205a47e67 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-struct kimage;
-/* Provide a dummy definition to avoid build failures. */
+/**
+ * crash_setup_regs() - save registers for the panic kernel
+ * @newregs: registers are saved here
+ * @oldregs: registers to be saved (may be %NULL)
+ *
+ * Function copies machine registers from @oldregs to @newregs. If @oldregs is
+ * %NULL then current registers are stored there.
+ */
 static inline void crash_setup_regs(struct pt_regs *newregs,
-                                        struct pt_regs *oldregs) { }
+                                   struct pt_regs *oldregs)
+{
+       if (oldregs) {
+               memcpy(newregs, oldregs, sizeof(*newregs));
+       } else {
+               __asm__ __volatile__ ("stmia %0, {r0 - r15}"
+                                     : : "r" (&newregs->ARM_r0));
+               __asm__ __volatile__ ("mrs %0, cpsr"
+                                     : "=r" (newregs->ARM_cpsr));
+       }
+}
 
 #endif /* __ASSEMBLY__ */
 
index c59842dc7cb8d8f2b3a3e140d3a17d8da575efe0..8a0dd18ba6427301ed4b802739a390dec64d12c2 100644 (file)
@@ -20,6 +20,7 @@ struct machine_desc {
         * by assembler code in head.S, head-common.S
         */
        unsigned int            nr;             /* architecture number  */
+       unsigned int            nr_irqs;        /* number of IRQs */
        unsigned int            phys_io;        /* start of physical io */
        unsigned int            io_pg_offst;    /* byte offset for io 
                                                 * page tabe entry      */
@@ -37,6 +38,7 @@ struct machine_desc {
        void                    (*fixup)(struct machine_desc *,
                                         struct tag *, char **,
                                         struct meminfo *);
+       void                    (*reserve)(void);/* reserve mem blocks  */
        void                    (*map_io)(void);/* IO mapping function  */
        void                    (*init_irq)(void);
        struct sys_timer        *timer;         /* system tick timer    */
index 8920b2d6e3b850634c501abe7f1512c6eea4a46f..ce3eee9fe26cbb055cbea6ab0d5567af4964b29a 100644 (file)
@@ -17,6 +17,7 @@ struct seq_file;
 /*
  * This is internal.  Do not use it.
  */
+extern unsigned int arch_nr_irqs;
 extern void (*init_arch_irq)(void);
 extern void init_FIQ(void);
 extern int show_fiq_list(struct seq_file *, void *);
index 742c2aaeb02031d4d4e77dbf11e653910887343b..d2fedb5aeb1f381d74dbdfd29516fbbfd0ea4e13 100644 (file)
@@ -27,6 +27,8 @@ struct map_desc {
 #define MT_MEMORY              9
 #define MT_ROM                 10
 #define MT_MEMORY_NONCACHED    11
+#define MT_MEMORY_DTCM         12
+#define MT_MEMORY_ITCM         13
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
index 52f0da1e97df28765c3dfe8a618a896727d5ec1b..16330bd0657cb172f5ff2d736ceb78c22dbdc23b 100644 (file)
@@ -46,6 +46,7 @@ struct pci_sys_data {
                                        /* IRQ mapping                          */
        int             (*map_irq)(struct pci_dev *, u8, u8);
        struct hw_pci   *hw;
+       void            *private_data;  /* platform controller private data     */
 };
 
 /*
diff --git a/arch/arm/include/asm/memblock.h b/arch/arm/include/asm/memblock.h
new file mode 100644 (file)
index 0000000..fdbc43b
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _ASM_ARM_MEMBLOCK_H
+#define _ASM_ARM_MEMBLOCK_H
+
+#ifdef CONFIG_MMU
+extern phys_addr_t lowmem_end_addr;
+#define MEMBLOCK_REAL_LIMIT    lowmem_end_addr
+#else
+#define MEMBLOCK_REAL_LIMIT    0
+#endif
+
+struct meminfo;
+struct machine_desc;
+
+extern void arm_memblock_init(struct meminfo *, struct machine_desc *);
+
+#endif
index 4312ee5e3d0b6d97b83f0655435c7514d43da671..23c2e8e5c0faaa09d81910456d4de63a96a513da 100644 (file)
 
 #endif /* !CONFIG_MMU */
 
+/*
+ * We fix the TCM memories max 32 KiB ITCM resp DTCM at these
+ * locations
+ */
+#ifdef CONFIG_HAVE_TCM
+#define ITCM_OFFSET    UL(0xfffe0000)
+#define DTCM_OFFSET    UL(0xfffe8000)
+#endif
+
 /*
  * Physical vs virtual RAM address space conversion.  These are
  * private definitions which should NOT be used outside memory.h
 #endif
 
 #ifndef arch_adjust_zones
-#define arch_adjust_zones(node,size,holes) do { } while (0)
+#define arch_adjust_zones(size,holes) do { } while (0)
 #elif !defined(CONFIG_ZONE_DMA)
 #error "custom arch_adjust_zones() requires CONFIG_ZONE_DMA"
 #endif
@@ -234,76 +243,11 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
  *  virt_to_page(k)    convert a _valid_ virtual address to struct page *
  *  virt_addr_valid(k) indicates whether a virtual address is valid
  */
-#ifndef CONFIG_DISCONTIGMEM
-
 #define ARCH_PFN_OFFSET                PHYS_PFN_OFFSET
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory)
 
-#define PHYS_TO_NID(addr)      (0)
-
-#else /* CONFIG_DISCONTIGMEM */
-
-/*
- * This is more complex.  We have a set of mem_map arrays spread
- * around in memory.
- */
-#include <linux/numa.h>
-
-#define arch_pfn_to_nid(pfn)   PFN_TO_NID(pfn)
-#define arch_local_page_offset(pfn, nid) LOCAL_MAP_NR((pfn) << PAGE_SHIFT)
-
-#define virt_to_page(kaddr)                                    \
-       (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr))
-
-#define virt_addr_valid(kaddr) (KVADDR_TO_NID(kaddr) < MAX_NUMNODES)
-
-/*
- * Common discontigmem stuff.
- *  PHYS_TO_NID is used by the ARM kernel/setup.c
- */
-#define PHYS_TO_NID(addr)      PFN_TO_NID((addr) >> PAGE_SHIFT)
-
-/*
- * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the mem_map of that node.
- */
-#define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr))
-
-/*
- * Given a page frame number, find the owning node of the memory
- * and returns the mem_map of that node.
- */
-#define PFN_TO_MAPBASE(pfn)    NODE_MEM_MAP(PFN_TO_NID(pfn))
-
-#ifdef NODE_MEM_SIZE_BITS
-#define NODE_MEM_SIZE_MASK     ((1 << NODE_MEM_SIZE_BITS) - 1)
-
-/*
- * Given a kernel address, find the home node of the underlying memory.
- */
-#define KVADDR_TO_NID(addr) \
-       (((unsigned long)(addr) - PAGE_OFFSET) >> NODE_MEM_SIZE_BITS)
-
-/*
- * Given a page frame number, convert it to a node id.
- */
-#define PFN_TO_NID(pfn) \
-       (((pfn) - PHYS_PFN_OFFSET) >> (NODE_MEM_SIZE_BITS - PAGE_SHIFT))
-
-/*
- * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory
- * and returns the index corresponding to the appropriate page in the
- * node's mem_map.
- */
-#define LOCAL_MAP_NR(addr) \
-       (((unsigned long)(addr) & NODE_MEM_SIZE_MASK) >> PAGE_SHIFT)
-
-#endif /* NODE_MEM_SIZE_BITS */
-
-#endif /* !CONFIG_DISCONTIGMEM */
-
 /*
  * Optional coherency support.  Currently used only by selected
  * Intel XSC3-based systems.
diff --git a/arch/arm/include/asm/mmzone.h b/arch/arm/include/asm/mmzone.h
deleted file mode 100644 (file)
index ae63a4f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  arch/arm/include/asm/mmzone.h
- *
- *  1999-12-29 Nicolas Pitre           Created
- *
- * 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 __ASM_MMZONE_H
-#define __ASM_MMZONE_H
-
-/*
- * Currently defined in arch/arm/mm/discontig.c
- */
-extern pg_data_t discontig_node_data[];
-
-/*
- * Return a pointer to the node data for node n.
- */
-#define NODE_DATA(nid)         (&discontig_node_data[nid])
-
-/*
- * NODE_MEM_MAP gives the kaddr for the mem_map of the node.
- */
-#define NODE_MEM_MAP(nid)      (NODE_DATA(nid)->node_mem_map)
-
-#include <mach/memory.h>
-
-#endif
index 9dcb11e590268f8bef4230557f477edb656588f3..c974be8913a76dda0a25e8c8f5ad1e7f3a03610d 100644 (file)
@@ -184,6 +184,42 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 #define predicate(x)           ((x) & 0xf0000000)
 #define PREDICATE_ALWAYS       0xe0000000
 
+/*
+ * kprobe-based event tracer support
+ */
+#include <linux/stddef.h>
+#include <linux/types.h>
+#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0))
+
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+extern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr);
+extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+                                              unsigned int n);
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:         pt_regs from which register value is gotten
+ * @offset:    offset number of the register.
+ *
+ * regs_get_register returns the value of a register whose offset from @regs.
+ * The @offset is the offset of the register in struct pt_regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+                                             unsigned int offset)
+{
+       if (unlikely(offset > MAX_REG_OFFSET))
+               return 0;
+       return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+/* Valid only for Kernel mode traps. */
+static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+{
+       return regs->ARM_sp;
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index f392fb4437afbd86b35807f16a152ab773df17f4..f1e5a9bca2491d982bda9fda1d40aa7b63b0cfd8 100644 (file)
@@ -201,8 +201,7 @@ static struct tagtable __tagtable_##fn __tag = { tag, fn }
 struct membank {
        unsigned long start;
        unsigned long size;
-       unsigned short node;
-       unsigned short highmem;
+       unsigned int highmem;
 };
 
 struct meminfo {
@@ -212,9 +211,8 @@ struct meminfo {
 
 extern struct meminfo meminfo;
 
-#define for_each_nodebank(iter,mi,no)                  \
-       for (iter = 0; iter < (mi)->nr_banks; iter++)   \
-               if ((mi)->bank[iter].node == no)
+#define for_each_bank(iter,mi)                         \
+       for (iter = 0; iter < (mi)->nr_banks; iter++)
 
 #define bank_pfn_start(bank)   __phys_to_pfn((bank)->start)
 #define bank_pfn_end(bank)     __phys_to_pfn((bank)->start + (bank)->size)
diff --git a/arch/arm/include/asm/stackprotector.h b/arch/arm/include/asm/stackprotector.h
new file mode 100644 (file)
index 0000000..de00332
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * GCC stack protector support.
+ *
+ * Stack protector works by putting predefined pattern at the start of
+ * the stack frame and verifying that it hasn't been overwritten when
+ * returning from the function.  The pattern is called stack canary
+ * and gcc expects it to be defined by a global variable called
+ * "__stack_chk_guard" on ARM.  This unfortunately means that on SMP
+ * we cannot have a different canary value per task.
+ */
+
+#ifndef _ASM_STACKPROTECTOR_H
+#define _ASM_STACKPROTECTOR_H 1
+
+#include <linux/random.h>
+#include <linux/version.h>
+
+extern unsigned long __stack_chk_guard;
+
+/*
+ * Initialize the stackprotector canary value.
+ *
+ * NOTE: this must only be called from functions that never return,
+ * and it must always be inlined.
+ */
+static __always_inline void boot_init_stack_canary(void)
+{
+       unsigned long canary;
+
+       /* Try to get a semi random initial value. */
+       get_random_bytes(&canary, sizeof(canary));
+       canary ^= LINUX_VERSION_CODE;
+
+       current->stack_canary = canary;
+       __stack_chk_guard = current->stack_canary;
+}
+
+#endif /* _ASM_STACKPROTECTOR_H */
index 5f4f48002734c2aa173ed8b8c0cd2294b64a8250..8ba1ccf82a0200283367db344ed79259f8d57c05 100644 (file)
@@ -83,7 +83,7 @@ void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
 
 void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
                                       struct pt_regs *),
-                    int sig, const char *name);
+                    int sig, int code, const char *name);
 
 #define xchg(ptr,x) \
        ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
new file mode 100644 (file)
index 0000000..e71d6ff
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __ASMARM_TLS_H
+#define __ASMARM_TLS_H
+
+#ifdef __ASSEMBLY__
+       .macro set_tls_none, tp, tmp1, tmp2
+       .endm
+
+       .macro set_tls_v6k, tp, tmp1, tmp2
+       mcr     p15, 0, \tp, c13, c0, 3         @ set TLS register
+       .endm
+
+       .macro set_tls_v6, tp, tmp1, tmp2
+       ldr     \tmp1, =elf_hwcap
+       ldr     \tmp1, [\tmp1, #0]
+       mov     \tmp2, #0xffff0fff
+       tst     \tmp1, #HWCAP_TLS               @ hardware TLS available?
+       mcrne   p15, 0, \tp, c13, c0, 3         @ yes, set TLS register
+       streq   \tp, [\tmp2, #-15]              @ set TLS value at 0xffff0ff0
+       .endm
+
+       .macro set_tls_software, tp, tmp1, tmp2
+       mov     \tmp1, #0xffff0fff
+       str     \tp, [\tmp1, #-15]              @ set TLS value at 0xffff0ff0
+       .endm
+#endif
+
+#ifdef CONFIG_TLS_REG_EMUL
+#define tls_emu                1
+#define has_tls_reg            1
+#define set_tls                set_tls_none
+#elif __LINUX_ARM_ARCH__ >= 7 ||                                       \
+       (__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K))
+#define tls_emu                0
+#define has_tls_reg            1
+#define set_tls                set_tls_v6k
+#elif __LINUX_ARM_ARCH__ == 6
+#define tls_emu                0
+#define has_tls_reg            (elf_hwcap & HWCAP_TLS)
+#define set_tls                set_tls_v6
+#else
+#define tls_emu                0
+#define has_tls_reg            0
+#define set_tls                set_tls_software
+#endif
+
+#endif /* __ASMARM_TLS_H */
index 422f3cc204a27310f99d9b25adebb9f49d16e3d0..3d5fc41ae8d38a7743b3bee9c55490135c19dcea 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Assembler-only file containing VFP macros and register definitions.
  */
+#include <asm/hwcap.h>
+
 #include "vfp.h"
 
 @ Macros to allow building with old toolkits (with no VFP support)
        LDC     p11, cr0, [\base],#32*4             @ FLDMIAD \base!, {d0-d15}
 #endif
 #ifdef CONFIG_VFPv3
+#if __LINUX_ARM_ARCH__ <= 6
+       ldr     \tmp, =elf_hwcap                    @ may not have MVFR regs
+       ldr     \tmp, [\tmp, #0]
+       tst     \tmp, #HWCAP_VFPv3D16
+       ldceq   p11, cr0, [\base],#32*4             @ FLDMIAD \base!, {d16-d31}
+       addne   \base, \base, #32*4                 @ step over unused register space
+#else
        VFPFMRX \tmp, MVFR0                         @ Media and VFP Feature Register 0
        and     \tmp, \tmp, #MVFR0_A_SIMD_MASK      @ A_SIMD field
        cmp     \tmp, #2                            @ 32 x 64bit registers?
        ldceql  p11, cr0, [\base],#32*4             @ FLDMIAD \base!, {d16-d31}
        addne   \base, \base, #32*4                 @ step over unused register space
+#endif
 #endif
        .endm
 
        STC     p11, cr0, [\base],#32*4             @ FSTMIAD \base!, {d0-d15}
 #endif
 #ifdef CONFIG_VFPv3
+#if __LINUX_ARM_ARCH__ <= 6
+       ldr     \tmp, =elf_hwcap                    @ may not have MVFR regs
+       ldr     \tmp, [\tmp, #0]
+       tst     \tmp, #HWCAP_VFPv3D16
+       stceq   p11, cr0, [\base],#32*4             @ FSTMIAD \base!, {d16-d31}
+       addne   \base, \base, #32*4                 @ step over unused register space
+#else
        VFPFMRX \tmp, MVFR0                         @ Media and VFP Feature Register 0
        and     \tmp, \tmp, #MVFR0_A_SIMD_MASK      @ A_SIMD field
        cmp     \tmp, #2                            @ 32 x 64bit registers?
        stceql  p11, cr0, [\base],#32*4             @ FSTMIAD \base!, {d16-d31}
        addne   \base, \base, #32*4                 @ step over unused register space
+#endif
 #endif
        .endm
index 26d302c28e1318b4aa5db81a491fcd6a82b0e6fa..980b78e31328156925f361cf5f6a2deac14c1500 100644 (file)
@@ -13,10 +13,12 @@ CFLAGS_REMOVE_return_address.o = -pg
 
 # Object file lists.
 
-obj-y          := compat.o elf.o entry-armv.o entry-common.o irq.o \
+obj-y          := elf.o entry-armv.o entry-common.o irq.o \
                   process.o ptrace.o return_address.o setup.o signal.o \
                   sys_arm.o stacktrace.o time.o traps.o
 
+obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
+
 obj-$(CONFIG_LEDS)             += leds.o
 obj-$(CONFIG_OC_ETM)           += etm.o
 
@@ -39,6 +41,7 @@ obj-$(CONFIG_ARM_THUMBEE)     += thumbee.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_ARM_UNWIND)       += unwind.o
 obj-$(CONFIG_HAVE_TCM)         += tcm.o
+obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
 obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
index 883511522fca9e83be970c2611fd2ce5a1a75a41..85f2a019f77bc93b17e0c55bf60693d18a8e2ffa 100644 (file)
@@ -40,6 +40,9 @@
 int main(void)
 {
   DEFINE(TSK_ACTIVE_MM,                offsetof(struct task_struct, active_mm));
+#ifdef CONFIG_CC_STACKPROTECTOR
+  DEFINE(TSK_STACK_CANARY,     offsetof(struct task_struct, stack_canary));
+#endif
   BLANK();
   DEFINE(TI_FLAGS,             offsetof(struct thread_info, flags));
   DEFINE(TI_PREEMPT,           offsetof(struct thread_info, preempt_count));
index 0a1385442f4344548bf20c5c0b28090f743e12b3..925652318b8b5df4cb7dce4383b99cee2640285b 100644 (file)
@@ -217,10 +217,3 @@ void __init convert_to_tag_list(struct tag *tags)
        struct param_struct *params = (struct param_struct *)tags;
        build_tag_list(params, &params->u2);
 }
-
-void __init squash_mem_tags(struct tag *tag)
-{
-       for (; tag->hdr.size; tag = tag_next(tag))
-               if (tag->hdr.tag == ATAG_MEM)
-                       tag->hdr.tag = ATAG_NONE;
-}
index 27e61a68bd1c5693909a4ac0dbbdb00c6663b684..39264ab1b9c640cd81447f4a54ec1f19c118fede 100644 (file)
@@ -9,5 +9,3 @@
 */
 
 extern void convert_to_tag_list(struct tag *tags);
-
-extern void squash_mem_tags(struct tag *tag);
diff --git a/arch/arm/kernel/crash_dump.c b/arch/arm/kernel/crash_dump.c
new file mode 100644 (file)
index 0000000..cd3b853
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/arm/kernel/crash_dump.c
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ * Author: Mika Westerberg
+ *
+ * This code is taken from arch/x86/kernel/crash_dump_64.c
+ *   Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *   Copyright (C) IBM Corporation, 2004. 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/errno.h>
+#include <linux/crash_dump.h>
+#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
+ * @buf: buffer where the copied page is placed
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page
+ * @userbuf: if set, @buf is int he user address space
+ *
+ * This function copies one page from old kernel memory into buffer pointed by
+ * @buf. If @buf is in userspace, set @userbuf to %1. Returns number of bytes
+ * copied or negative error in case of failure.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+                        size_t csize, unsigned long offset,
+                        int userbuf)
+{
+       void *vaddr;
+
+       if (!csize)
+               return 0;
+
+       vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+       if (!vaddr)
+               return -ENOMEM;
+
+       if (userbuf) {
+               if (copy_to_user(buf, vaddr + offset, csize)) {
+                       iounmap(vaddr);
+                       return -EFAULT;
+               }
+       } else {
+               memcpy(buf, vaddr + offset, csize);
+       }
+
+       iounmap(vaddr);
+       return csize;
+}
index 3fd7861de4d16c508ee424e52281de0dc39a4db7..bb8e93a76407241042345c51273690f6cdc35578 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/thread_notify.h>
 #include <asm/unwind.h>
 #include <asm/unistd.h>
+#include <asm/tls.h>
 
 #include "entry-header.S"
 
@@ -735,11 +736,11 @@ ENTRY(__switch_to)
 #ifdef CONFIG_MMU
        ldr     r6, [r2, #TI_CPU_DOMAIN]
 #endif
-#if defined(CONFIG_HAS_TLS_REG)
-       mcr     p15, 0, r3, c13, c0, 3          @ set TLS register
-#elif !defined(CONFIG_TLS_REG_EMUL)
-       mov     r4, #0xffff0fff
-       str     r3, [r4, #-15]                  @ TLS val at 0xffff0ff0
+       set_tls r3, r4, r5
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       ldr     r7, [r2, #TI_TASK]
+       ldr     r8, =__stack_chk_guard
+       ldr     r7, [r7, #TSK_STACK_CANARY]
 #endif
 #ifdef CONFIG_MMU
        mcr     p15, 0, r6, c3, c0, 0           @ Set domain register
@@ -749,6 +750,9 @@ ENTRY(__switch_to)
        ldr     r0, =thread_notify_head
        mov     r1, #THREAD_NOTIFY_SWITCH
        bl      atomic_notifier_call_chain
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       str     r7, [r8]
+#endif
  THUMB(        mov     ip, r4                     )
        mov     r0, r5
  ARM(  ldmia   r4, {r4 - sl, fp, sp, pc}  )    @ Load all regs saved previously
@@ -1005,17 +1009,12 @@ kuser_cmpxchg_fixup:
  */
 
 __kuser_get_tls:                               @ 0xffff0fe0
-
-#if !defined(CONFIG_HAS_TLS_REG) && !defined(CONFIG_TLS_REG_EMUL)
-       ldr     r0, [pc, #(16 - 8)]             @ TLS stored at 0xffff0ff0
-#else
-       mrc     p15, 0, r0, c13, c0, 3          @ read TLS register
-#endif
+       ldr     r0, [pc, #(16 - 8)]     @ read TLS, set in kuser_get_tls_init
        usr_ret lr
-
-       .rep    5
-       .word   0                       @ pad up to __kuser_helper_version
-       .endr
+       mrc     p15, 0, r0, c13, c0, 3  @ 0xffff0fe8 hardware TLS code
+       .rep    4
+       .word   0                       @ 0xffff0ff0 software TLS value, then
+       .endr                           @ pad up to __kuser_helper_version
 
 /*
  * Reference declaration:
index 3b3d2c80509c0bb4c3499f944414a11425f6e5e6..c0d5c3b3a760fa79624657ebc495b1d7b81b8c66 100644 (file)
 #define irq_finish(irq) do { } while (0)
 #endif
 
+unsigned int arch_nr_irqs;
 void (*init_arch_irq)(void) __initdata = NULL;
 unsigned long irq_err_count;
 
 int show_interrupts(struct seq_file *p, void *v)
 {
        int i = *(loff_t *) v, cpu;
+       struct irq_desc *desc;
        struct irqaction * action;
        unsigned long flags;
 
@@ -67,24 +69,25 @@ int show_interrupts(struct seq_file *p, void *v)
                seq_putc(p, '\n');
        }
 
-       if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
+       if (i < nr_irqs) {
+               desc = irq_to_desc(i);
+               raw_spin_lock_irqsave(&desc->lock, flags);
+               action = desc->action;
                if (!action)
                        goto unlock;
 
                seq_printf(p, "%3d: ", i);
                for_each_present_cpu(cpu)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
-               seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-");
+               seq_printf(p, " %10s", desc->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);
-       } else if (i == NR_IRQS) {
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
+       } else if (i == nr_irqs) {
 #ifdef CONFIG_FIQ
                show_fiq_list(p, v);
 #endif
@@ -112,7 +115,7 @@ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
         * Some hardware gives randomly wrong interrupts.  Rather
         * than crashing, do something sensible.
         */
-       if (unlikely(irq >= NR_IRQS)) {
+       if (unlikely(irq >= nr_irqs)) {
                if (printk_ratelimit())
                        printk(KERN_WARNING "Bad IRQ%u\n", irq);
                ack_bad_irq(irq);
@@ -132,12 +135,12 @@ void set_irq_flags(unsigned int irq, unsigned int iflags)
        struct irq_desc *desc;
        unsigned long flags;
 
-       if (irq >= NR_IRQS) {
+       if (irq >= nr_irqs) {
                printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
                return;
        }
 
-       desc = irq_desc + irq;
+       desc = irq_to_desc(irq);
        raw_spin_lock_irqsave(&desc->lock, flags);
        desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
        if (iflags & IRQF_VALID)
@@ -151,14 +154,25 @@ void set_irq_flags(unsigned int irq, unsigned int iflags)
 
 void __init init_IRQ(void)
 {
+       struct irq_desc *desc;
        int irq;
 
-       for (irq = 0; irq < NR_IRQS; irq++)
-               irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
+       for (irq = 0; irq < nr_irqs; irq++) {
+               desc = irq_to_desc_alloc_node(irq, 0);
+               desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
+       }
 
        init_arch_irq();
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+int __init arch_probe_nr_irqs(void)
+{
+       nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS;
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_HOTPLUG_CPU
 
 static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
@@ -178,10 +192,9 @@ static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
 void migrate_irqs(void)
 {
        unsigned int i, cpu = smp_processor_id();
+       struct irq_desc *desc;
 
-       for (i = 0; i < NR_IRQS; i++) {
-               struct irq_desc *desc = irq_desc + i;
-
+       for_each_irq_desc(i, desc) {
                if (desc->node == cpu) {
                        unsigned int newcpu = cpumask_any_and(desc->affinity,
                                                              cpu_online_mask);
index 598ca61e7bca8496a853128a433dc7d1dfba0edf..1fc74cbd1a193ee4dcd2fd50afdd279804d9e5fd 100644 (file)
@@ -37,12 +37,12 @@ void machine_kexec_cleanup(struct kimage *image)
 {
 }
 
-void machine_shutdown(void)
-{
-}
-
 void machine_crash_shutdown(struct pt_regs *regs)
 {
+       local_irq_disable();
+       crash_save_cpu(regs, smp_processor_id());
+
+       printk(KERN_INFO "Loading crashdump kernel...\n");
 }
 
 void machine_kexec(struct kimage *image)
@@ -74,7 +74,11 @@ void machine_kexec(struct kimage *image)
                           (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
        printk(KERN_INFO "Bye!\n");
 
-       cpu_proc_fin();
+       local_irq_disable();
+       local_fiq_disable();
        setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
+       flush_cache_all();
+       cpu_proc_fin();
+       flush_cache_all();
        cpu_reset(reboot_code_buffer_phys);
 }
index a4a9cc88bec73a525a9edd4bdc7db94cea370ce9..401e38be1f787c16e7b36d6429406a05229d83da 100644 (file)
@@ -28,7 +28,9 @@
 #include <linux/tick.h>
 #include <linux/utsname.h>
 #include <linux/uaccess.h>
+#include <linux/random.h>
 
+#include <asm/cacheflush.h>
 #include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/time.h>
 
+#ifdef CONFIG_CC_STACKPROTECTOR
+#include <linux/stackprotector.h>
+unsigned long __stack_chk_guard __read_mostly;
+EXPORT_SYMBOL(__stack_chk_guard);
+#endif
+
 static const char *processor_modes[] = {
   "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
   "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
@@ -84,10 +92,9 @@ __setup("hlt", hlt_setup);
 
 void arm_machine_restart(char mode, const char *cmd)
 {
-       /*
-        * Clean and disable cache, and turn off interrupts
-        */
-       cpu_proc_fin();
+       /* Disable interrupts first */
+       local_irq_disable();
+       local_fiq_disable();
 
        /*
         * Tell the mm system that we are going to reboot -
@@ -96,6 +103,15 @@ void arm_machine_restart(char mode, const char *cmd)
         */
        setup_mm_for_reboot(mode);
 
+       /* Clean and invalidate caches */
+       flush_cache_all();
+
+       /* Turn off caching */
+       cpu_proc_fin();
+
+       /* Push out any further dirty data, and ensure cache is empty */
+       flush_cache_all();
+
        /*
         * Now call the architecture specific reboot code.
         */
@@ -189,19 +205,29 @@ int __init reboot_setup(char *str)
 
 __setup("reboot=", reboot_setup);
 
-void machine_halt(void)
+void machine_shutdown(void)
 {
+#ifdef CONFIG_SMP
+       smp_send_stop();
+#endif
 }
 
+void machine_halt(void)
+{
+       machine_shutdown();
+       while (1);
+}
 
 void machine_power_off(void)
 {
+       machine_shutdown();
        if (pm_power_off)
                pm_power_off();
 }
 
 void machine_restart(char *cmd)
 {
+       machine_shutdown();
        arm_pm_restart(reboot_mode, cmd);
 }
 
@@ -426,3 +452,9 @@ unsigned long get_wchan(struct task_struct *p)
        } while (count ++ < 16);
        return 0;
 }
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+       unsigned long range_end = mm->brk + 0x02000000;
+       return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
+}
index 3f562a7c0a99445f3747ec0d0198d4f53a4d83fd..f99d489822d50fb23e46f4e7760411b766e040e7 100644 (file)
 #define BREAKINST_THUMB        0xde01
 #endif
 
+struct pt_regs_offset {
+       const char *name;
+       int offset;
+};
+
+#define REG_OFFSET_NAME(r) \
+       {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+       REG_OFFSET_NAME(r0),
+       REG_OFFSET_NAME(r1),
+       REG_OFFSET_NAME(r2),
+       REG_OFFSET_NAME(r3),
+       REG_OFFSET_NAME(r4),
+       REG_OFFSET_NAME(r5),
+       REG_OFFSET_NAME(r6),
+       REG_OFFSET_NAME(r7),
+       REG_OFFSET_NAME(r8),
+       REG_OFFSET_NAME(r9),
+       REG_OFFSET_NAME(r10),
+       REG_OFFSET_NAME(fp),
+       REG_OFFSET_NAME(ip),
+       REG_OFFSET_NAME(sp),
+       REG_OFFSET_NAME(lr),
+       REG_OFFSET_NAME(pc),
+       REG_OFFSET_NAME(cpsr),
+       REG_OFFSET_NAME(ORIG_r0),
+       REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:      the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (!strcmp(roff->name, name))
+                       return roff->offset;
+       return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:    the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+       const struct pt_regs_offset *roff;
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (roff->offset == offset)
+                       return roff->name;
+       return NULL;
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @addr:      address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
+{
+       return ((addr & ~(THREAD_SIZE - 1))  ==
+               (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @n:         stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
+{
+       unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+       addr += n;
+       if (regs_within_kernel_stack(regs, (unsigned long)addr))
+               return *addr;
+       else
+               return 0;
+}
+
 /*
  * this routine will get a word off of the processes privileged stack.
  * the offset is how far from the base addr as stored in the THREAD.
index 61930eb0902941030e3e180aca40f6f82697e39e..fd26f8d65151a949e6ecff394f0146258882b9d6 100644 (file)
@@ -10,6 +10,12 @@ relocate_new_kernel:
        ldr     r0,kexec_indirection_page
        ldr     r1,kexec_start_address
 
+       /*
+        * If there is no indirection page (we are doing crashdumps)
+        * skip any relocation.
+        */
+       cmp     r0, #0
+       beq     2f
 
 0:     /* top, read another word for the indirection page */
        ldr     r3, [r0],#4
index 122d999bdc7ca0c8f690355a101f59f1ea8152f8..d5231ae7355aa286bf5503e0180954f84e4f6022 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/screen_info.h>
 #include <linux/init.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
+#include <linux/memblock.h>
 
 #include <asm/unified.h>
 #include <asm/cpu.h>
@@ -44,7 +47,9 @@
 #include <asm/traps.h>
 #include <asm/unwind.h>
 
+#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
 #include "compat.h"
+#endif
 #include "atags.h"
 #include "tcm.h"
 
@@ -269,6 +274,21 @@ static void __init cacheid_init(void)
 extern struct proc_info_list *lookup_processor_type(unsigned int);
 extern struct machine_desc *lookup_machine_type(unsigned int);
 
+static void __init feat_v6_fixup(void)
+{
+       int id = read_cpuid_id();
+
+       if ((id & 0xff0f0000) != 0x41070000)
+               return;
+
+       /*
+        * HWCAP_TLS is available only on 1136 r1p0 and later,
+        * see also kuser_get_tls_init.
+        */
+       if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
+               elf_hwcap &= ~HWCAP_TLS;
+}
+
 static void __init setup_processor(void)
 {
        struct proc_info_list *list;
@@ -311,6 +331,8 @@ static void __init setup_processor(void)
        elf_hwcap &= ~HWCAP_THUMB;
 #endif
 
+       feat_v6_fixup();
+
        cacheid_init();
        cpu_proc_init();
 }
@@ -402,13 +424,12 @@ static int __init arm_add_memory(unsigned long start, unsigned long size)
        size -= start & ~PAGE_MASK;
        bank->start = PAGE_ALIGN(start);
        bank->size  = size & PAGE_MASK;
-       bank->node  = PHYS_TO_NID(start);
 
        /*
         * Check whether this memory region has non-zero size or
         * invalid node number.
         */
-       if (bank->size == 0 || bank->node >= MAX_NUMNODES)
+       if (bank->size == 0)
                return -EINVAL;
 
        meminfo.nr_banks++;
@@ -663,6 +684,86 @@ static int __init customize_machine(void)
 }
 arch_initcall(customize_machine);
 
+#ifdef CONFIG_KEXEC
+static inline unsigned long long get_total_mem(void)
+{
+       unsigned long total;
+
+       total = max_low_pfn - min_low_pfn;
+       return total << PAGE_SHIFT;
+}
+
+/**
+ * reserve_crashkernel() - reserves memory are for crash kernel
+ *
+ * This function reserves memory area given in "crashkernel=" kernel command
+ * line parameter. The memory reserved is used by a dump capture kernel when
+ * primary kernel is crashing.
+ */
+static void __init reserve_crashkernel(void)
+{
+       unsigned long long crash_size, crash_base;
+       unsigned long long total_mem;
+       int ret;
+
+       total_mem = get_total_mem();
+       ret = parse_crashkernel(boot_command_line, total_mem,
+                               &crash_size, &crash_base);
+       if (ret)
+               return;
+
+       ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
+       if (ret < 0) {
+               printk(KERN_WARNING "crashkernel reservation failed - "
+                      "memory is in use (0x%lx)\n", (unsigned long)crash_base);
+               return;
+       }
+
+       printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+              "for crashkernel (System RAM: %ldMB)\n",
+              (unsigned long)(crash_size >> 20),
+              (unsigned long)(crash_base >> 20),
+              (unsigned long)(total_mem >> 20));
+
+       crashk_res.start = crash_base;
+       crashk_res.end = crash_base + crash_size - 1;
+       insert_resource(&iomem_resource, &crashk_res);
+}
+#else
+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))
+               if (tag->hdr.tag == ATAG_MEM)
+                       tag->hdr.tag = ATAG_NONE;
+}
+
 void __init setup_arch(char **cmdline_p)
 {
        struct tag *tags = (struct tag *)&init_tags;
@@ -683,12 +784,14 @@ void __init setup_arch(char **cmdline_p)
        else if (mdesc->boot_params)
                tags = phys_to_virt(mdesc->boot_params);
 
+#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
        /*
         * If we have the old style parameters, convert them to
         * a tag list.
         */
        if (tags->hdr.tag != ATAG_CORE)
                convert_to_tag_list(tags);
+#endif
        if (tags->hdr.tag != ATAG_CORE)
                tags = (struct tag *)&init_tags;
 
@@ -716,12 +819,15 @@ void __init setup_arch(char **cmdline_p)
 
        parse_early_param();
 
+       arm_memblock_init(&meminfo, mdesc);
+
        paging_init(mdesc);
        request_standard_resources(&meminfo, mdesc);
 
 #ifdef CONFIG_SMP
        smp_init_cpus();
 #endif
+       reserve_crashkernel();
 
        cpu_init();
        tcm_init();
@@ -729,6 +835,7 @@ void __init setup_arch(char **cmdline_p)
        /*
         * Set up various architecture-specific pointers
         */
+       arch_nr_irqs = mdesc->nr_irqs;
        init_arch_irq = mdesc->init_irq;
        system_timer = mdesc->timer;
        init_machine = mdesc->init_machine;
index b8c3d0f689d9560cc33a7e8ec06958ad216e7ef1..40dc74f2b27f3362f8739f5e9898963dd27a221b 100644 (file)
@@ -429,7 +429,11 @@ static void smp_timer_broadcast(const struct cpumask *mask)
 {
        send_ipi_message(mask, IPI_TIMER);
 }
+#else
+#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)
 {
@@ -444,7 +448,6 @@ static void local_timer_setup(struct clock_event_device *evt)
        evt->rating     = 400;
        evt->mult       = 1;
        evt->set_mode   = broadcast_timer_set_mode;
-       evt->broadcast  = smp_timer_broadcast;
 
        clockevents_register_device(evt);
 }
@@ -456,6 +459,7 @@ void __cpuinit percpu_timer_setup(void)
        struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
 
        evt->cpumask = cpumask_of(cpu);
+       evt->broadcast = smp_timer_broadcast;
 
        local_timer_setup(evt);
 }
@@ -467,10 +471,13 @@ static DEFINE_SPINLOCK(stop_lock);
  */
 static void ipi_cpu_stop(unsigned int cpu)
 {
-       spin_lock(&stop_lock);
-       printk(KERN_CRIT "CPU%u: stopping\n", cpu);
-       dump_stack();
-       spin_unlock(&stop_lock);
+       if (system_state == SYSTEM_BOOTING ||
+           system_state == SYSTEM_RUNNING) {
+               spin_lock(&stop_lock);
+               printk(KERN_CRIT "CPU%u: stopping\n", cpu);
+               dump_stack();
+               spin_unlock(&stop_lock);
+       }
 
        set_cpu_online(cpu, false);
 
index 7c5f0c024db7e468aba3a185bded3bf3fde7073a..35882fbf37f90063723d3247352a3c05af480f99 100644 (file)
@@ -132,7 +132,8 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
        twd_calibrate_rate();
 
        clk->name = "local_timer";
-       clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+                       CLOCK_EVT_FEAT_C3STOP;
        clk->rating = 350;
        clk->set_mode = twd_set_mode;
        clk->set_next_event = twd_set_next_event;
index e50303868f1b62dd3853667d4a1445629eb4999c..26685c2f7a49d11b16421f5cad55c3c5109a27ea 100644 (file)
 #include <linux/ioport.h>
 #include <linux/genalloc.h>
 #include <linux/string.h> /* memcpy */
-#include <asm/page.h> /* PAGE_SHIFT */
 #include <asm/cputype.h>
 #include <asm/mach/map.h>
 #include <mach/memory.h>
 #include "tcm.h"
 
-/* Scream and warn about misuse */
-#if !defined(ITCM_OFFSET) || !defined(ITCM_END) || \
-    !defined(DTCM_OFFSET) || !defined(DTCM_END)
-#error "TCM support selected but offsets not defined!"
-#endif
-
 static struct gen_pool *tcm_pool;
 
 /* TCM section definitions from the linker */
 extern char __itcm_start, __sitcm_text, __eitcm_text;
 extern char __dtcm_start, __sdtcm_data, __edtcm_data;
 
+/* These will be increased as we run */
+u32 dtcm_end = DTCM_OFFSET;
+u32 itcm_end = ITCM_OFFSET;
+
 /*
  * TCM memory resources
  */
 static struct resource dtcm_res = {
        .name = "DTCM RAM",
        .start = DTCM_OFFSET,
-       .end = DTCM_END,
+       .end = DTCM_OFFSET,
        .flags = IORESOURCE_MEM
 };
 
 static struct resource itcm_res = {
        .name = "ITCM RAM",
        .start = ITCM_OFFSET,
-       .end = ITCM_END,
+       .end = ITCM_OFFSET,
        .flags = IORESOURCE_MEM
 };
 
@@ -52,8 +49,8 @@ static struct map_desc dtcm_iomap[] __initdata = {
        {
                .virtual        = DTCM_OFFSET,
                .pfn            = __phys_to_pfn(DTCM_OFFSET),
-               .length         = (DTCM_END - DTCM_OFFSET + 1),
-               .type           = MT_UNCACHED
+               .length         = 0,
+               .type           = MT_MEMORY_DTCM
        }
 };
 
@@ -61,8 +58,8 @@ static struct map_desc itcm_iomap[] __initdata = {
        {
                .virtual        = ITCM_OFFSET,
                .pfn            = __phys_to_pfn(ITCM_OFFSET),
-               .length         = (ITCM_END - ITCM_OFFSET + 1),
-               .type           = MT_UNCACHED
+               .length         = 0,
+               .type           = MT_MEMORY_ITCM
        }
 };
 
@@ -93,14 +90,24 @@ void tcm_free(void *addr, size_t len)
 }
 EXPORT_SYMBOL(tcm_free);
 
-
-static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
+static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
+                                 u32 *offset)
 {
        const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128,
                                    256, 512, 1024, -1, -1, -1, -1 };
        u32 tcm_region;
        int tcm_size;
 
+       /*
+        * If there are more than one TCM bank of this type,
+        * select the TCM bank to operate on in the TCM selection
+        * register.
+        */
+       if (banks > 1)
+               asm("mcr        p15, 0, %0, c9, c2, 0"
+                   : /* No output operands */
+                   : "r" (bank));
+
        /* Read the special TCM region register c9, 0 */
        if (!type)
                asm("mrc        p15, 0, %0, c9, c1, 0"
@@ -111,26 +118,24 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
 
        tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f];
        if (tcm_size < 0) {
-               pr_err("CPU: %sTCM of unknown size!\n",
-                       type ? "I" : "D");
+               pr_err("CPU: %sTCM%d of unknown size\n",
+                      type ? "I" : "D", bank);
+               return -EINVAL;
+       } else if (tcm_size > 32) {
+               pr_err("CPU: %sTCM%d larger than 32k found\n",
+                      type ? "I" : "D", bank);
+               return -EINVAL;
        } else {
-               pr_info("CPU: found %sTCM %dk @ %08x, %senabled\n",
+               pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n",
                        type ? "I" : "D",
+                       bank,
                        tcm_size,
                        (tcm_region & 0xfffff000U),
                        (tcm_region & 1) ? "" : "not ");
        }
 
-       if (tcm_size != expected_size) {
-               pr_crit("CPU: %sTCM was detected %dk but expected %dk!\n",
-                      type ? "I" : "D",
-                      tcm_size,
-                      expected_size);
-               /* Adjust to the expected size? what can we do... */
-       }
-
        /* Force move the TCM bank to where we want it, enable */
-       tcm_region = offset | (tcm_region & 0x00000ffeU) | 1;
+       tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1;
 
        if (!type)
                asm("mcr        p15, 0, %0, c9, c1, 0"
@@ -141,10 +146,15 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
                    : /* No output operands */
                    : "r" (tcm_region));
 
-       pr_debug("CPU: moved %sTCM %dk to %08x, enabled\n",
-                type ? "I" : "D",
-                tcm_size,
-                (tcm_region & 0xfffff000U));
+       /* Increase offset */
+       *offset += (tcm_size << 10);
+
+       pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n",
+               type ? "I" : "D",
+               bank,
+               tcm_size,
+               (tcm_region & 0xfffff000U));
+       return 0;
 }
 
 /*
@@ -153,34 +163,52 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
 void __init tcm_init(void)
 {
        u32 tcm_status = read_cpuid_tcmstatus();
+       u8 dtcm_banks = (tcm_status >> 16) & 0x03;
+       u8 itcm_banks = (tcm_status & 0x03);
        char *start;
        char *end;
        char *ram;
+       int ret;
+       int i;
 
        /* Setup DTCM if present */
-       if (tcm_status & (1 << 16)) {
-               setup_tcm_bank(0, DTCM_OFFSET,
-                              (DTCM_END - DTCM_OFFSET + 1) >> 10);
+       if (dtcm_banks > 0) {
+               for (i = 0; i < dtcm_banks; i++) {
+                       ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
+                       if (ret)
+                               return;
+               }
+               dtcm_res.end = dtcm_end - 1;
                request_resource(&iomem_resource, &dtcm_res);
+               dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
                iotable_init(dtcm_iomap, 1);
                /* Copy data from RAM to DTCM */
                start = &__sdtcm_data;
                end   = &__edtcm_data;
                ram   = &__dtcm_start;
+               /* This means you compiled more code than fits into DTCM */
+               BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET));
                memcpy(start, ram, (end-start));
                pr_debug("CPU DTCM: copied data from %p - %p\n", start, end);
        }
 
        /* Setup ITCM if present */
-       if (tcm_status & 1) {
-               setup_tcm_bank(1, ITCM_OFFSET,
-                              (ITCM_END - ITCM_OFFSET + 1) >> 10);
+       if (itcm_banks > 0) {
+               for (i = 0; i < itcm_banks; i++) {
+                       ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
+                       if (ret)
+                               return;
+               }
+               itcm_res.end = itcm_end - 1;
                request_resource(&iomem_resource, &itcm_res);
+               itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
                iotable_init(itcm_iomap, 1);
                /* Copy code from RAM to ITCM */
                start = &__sitcm_text;
                end   = &__eitcm_text;
                ram   = &__itcm_start;
+               /* This means you compiled more code than fits into ITCM */
+               BUG_ON((end - start) > (itcm_end - ITCM_OFFSET));
                memcpy(start, ram, (end-start));
                pr_debug("CPU ITCM: copied code from %p - %p\n", start, end);
        }
@@ -208,10 +236,10 @@ static int __init setup_tcm_pool(void)
        pr_debug("Setting up TCM memory pool\n");
 
        /* Add the rest of DTCM to the TCM pool */
-       if (tcm_status & (1 << 16)) {
-               if (dtcm_pool_start < DTCM_END) {
+       if (tcm_status & (0x03 << 16)) {
+               if (dtcm_pool_start < dtcm_end) {
                        ret = gen_pool_add(tcm_pool, dtcm_pool_start,
-                                          DTCM_END - dtcm_pool_start + 1, -1);
+                                          dtcm_end - dtcm_pool_start, -1);
                        if (ret) {
                                pr_err("CPU DTCM: could not add DTCM " \
                                       "remainder to pool!\n");
@@ -219,16 +247,16 @@ static int __init setup_tcm_pool(void)
                        }
                        pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \
                                 "the TCM memory pool\n",
-                                DTCM_END - dtcm_pool_start + 1,
+                                dtcm_end - dtcm_pool_start,
                                 dtcm_pool_start);
                }
        }
 
        /* Add the rest of ITCM to the TCM pool */
-       if (tcm_status & 1) {
-               if (itcm_pool_start < ITCM_END) {
+       if (tcm_status & 0x03) {
+               if (itcm_pool_start < itcm_end) {
                        ret = gen_pool_add(tcm_pool, itcm_pool_start,
-                                          ITCM_END - itcm_pool_start + 1, -1);
+                                          itcm_end - itcm_pool_start, -1);
                        if (ret) {
                                pr_err("CPU ITCM: could not add ITCM " \
                                       "remainder to pool!\n");
@@ -236,7 +264,7 @@ static int __init setup_tcm_pool(void)
                        }
                        pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \
                                 "the TCM memory pool\n",
-                                ITCM_END - itcm_pool_start + 1,
+                                itcm_end - itcm_pool_start,
                                 itcm_pool_start);
                }
        }
index 1621e5327b2a72a6c9197e95615928e749aa5f41..cda78d59aa31b2971ed897b9db78afd6bfb0f36e 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/unistd.h>
 #include <asm/traps.h>
 #include <asm/unwind.h>
+#include <asm/tls.h>
 
 #include "ptrace.h"
 #include "signal.h"
@@ -518,17 +519,20 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
 
        case NR(set_tls):
                thread->tp_value = regs->ARM_r0;
-#if defined(CONFIG_HAS_TLS_REG)
-               asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) );
-#elif !defined(CONFIG_TLS_REG_EMUL)
-               /*
-                * User space must never try to access this directly.
-                * Expect your app to break eventually if you do so.
-                * The user helper at 0xffff0fe0 must be used instead.
-                * (see entry-armv.S for details)
-                */
-               *((unsigned int *)0xffff0ff0) = regs->ARM_r0;
-#endif
+               if (tls_emu)
+                       return 0;
+               if (has_tls_reg) {
+                       asm ("mcr p15, 0, %0, c13, c0, 3"
+                               : : "r" (regs->ARM_r0));
+               } else {
+                       /*
+                        * User space must never try to access this directly.
+                        * Expect your app to break eventually if you do so.
+                        * The user helper at 0xffff0fe0 must be used instead.
+                        * (see entry-armv.S for details)
+                        */
+                       *((unsigned int *)0xffff0ff0) = regs->ARM_r0;
+               }
                return 0;
 
 #ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG
@@ -743,6 +747,16 @@ void __init trap_init(void)
        return;
 }
 
+static void __init kuser_get_tls_init(unsigned long vectors)
+{
+       /*
+        * vectors + 0xfe0 = __kuser_get_tls
+        * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
+        */
+       if (tls_emu || has_tls_reg)
+               memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
+}
+
 void __init early_trap_init(void)
 {
        unsigned long vectors = CONFIG_VECTORS_BASE;
@@ -760,6 +774,11 @@ void __init early_trap_init(void)
        memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
        memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
 
+       /*
+        * Do processor specific fixups for the kuser helpers
+        */
+       kuser_get_tls_init(vectors);
+
        /*
         * Copy signal return handlers into the vector page, and
         * set sigreturn to be a pointer to these.
index 030ba7219f482bfd9873b196d1a8634d5fc2eacb..59ff42ddf0aed656f3def2c44859f0eec414b1d3 100644 (file)
@@ -41,7 +41,6 @@ else
 endif
 
 lib-$(CONFIG_ARCH_RPC)         += ecard.o io-acorn.o floppydma.o
-lib-$(CONFIG_ARCH_L7200)       += io-acorn.o
 lib-$(CONFIG_ARCH_SHARK)       += io-shark.o
 
 $(obj)/csumpartialcopy.o:      $(obj)/csumpartialcopygeneric.S
index 59ff6fdc1e634835575846693fb0828a05c66a55..7d08b43d2c0e496fc704378301b82d3b34d93f3a 100644 (file)
@@ -71,7 +71,7 @@
                .pushsection .fixup,"ax"
                .align  4
 9001:          mov     r4, #-EFAULT
-               ldr     r5, [fp, #4]            @ *err_ptr
+               ldr     r5, [sp, #8*4]          @ *err_ptr
                str     r4, [r5]
                ldmia   sp, {r1, r2}            @ retrieve dst, len
                add     r2, r2, r1
index c00822543d9f78a307c4a7c7f3c576db75c2efb4..4f93c567a35a3acb8969d5ae7951bfc2e8f008e4 100644 (file)
 
 #define PHYS_OFFSET    UL(0xf0000000)
 
-/*
- * The nodes are the followings:
- *
- *   node 0: 0xf000.0000 - 0xf3ff.ffff
- *   node 1: 0xf400.0000 - 0xf7ff.ffff
- *   node 2: 0xf800.0000 - 0xfbff.ffff
- *   node 3: 0xfc00.0000 - 0xffff.ffff
- */
-#define NODE_MEM_SIZE_BITS     26
-
 #endif /* __ASM_ARCH_MEMORY_H */
index 841eaf8f27e221dfa600178e4d20ac0d56ddeaad..939bccd70569846987c6ddb304cd22c7de730bf7 100644 (file)
@@ -366,6 +366,17 @@ config MACH_STAMP9G20
 
 endif
 
+if (ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
+comment "AT91SAM9260/AT91SAM9G20 boards"
+
+config MACH_SNAPPER_9260
+        bool "Bluewater Systems Snapper 9260/9G20 module"
+        help
+          Select this if you are using the Bluewater Systems Snapper 9260 or
+          Snapper 9G20 modules.
+          <http://www.bluewatersys.com/>
+endif
+
 # ----------------------------------------------------------
 
 if ARCH_AT91SAM9G45
index c1f821e58222b77257e875c3ce5a72ea2be6429d..ca2ac003f41f5666fb8da8c1e23b34ab3e363ea6 100644 (file)
@@ -66,6 +66,9 @@ obj-$(CONFIG_MACH_CPU9G20)    += board-cpu9krea.o
 obj-$(CONFIG_MACH_STAMP9G20)   += board-stamp9g20.o
 obj-$(CONFIG_MACH_PORTUXG20)   += board-stamp9g20.o
 
+# AT91SAM9260/AT91SAM9G20 board-specific support
+obj-$(CONFIG_MACH_SNAPPER_9260)        += board-snapper9260.o
+
 # AT91SAM9G45 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o
 
index 85166b7e69a18235969336742526c2961c486d66..753c0d31a3d3f0b407cfe20b68f5ba66189cd1a7 100644 (file)
@@ -20,6 +20,7 @@
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 #include "clock.h"
@@ -176,6 +177,13 @@ static struct clk mmc1_clk = {
        .type           = CLK_TYPE_PERIPHERAL,
 };
 
+/* Video decoder clock - Only for sam9m10/sam9m11 */
+static struct clk vdec_clk = {
+       .name           = "vdec_clk",
+       .pmc_mask       = 1 << AT91SAM9G45_ID_VDEC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+
 /* One additional fake clock for ohci */
 static struct clk ohci_clk = {
        .name           = "ohci_clk",
@@ -239,6 +247,9 @@ static void __init at91sam9g45_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       if (cpu_is_at91sam9m10() || cpu_is_at91sam9m11())
+               clk_register(&vdec_clk);
+
        clk_register(&pck0);
        clk_register(&pck1);
 }
index a4102d72cc9b1c8e9d323f432fb5873b2144cc44..c49f5c003ee10d9fbad7a6f076f0e1dc58b0d653 100644 (file)
@@ -26,6 +26,9 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/at73c213.h>
 #include <linux/clk.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -235,6 +238,46 @@ static struct gpio_led ek_leds[] = {
        }
 };
 
+#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
+static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
+       REGULATOR_SUPPLY("AVDD", "0-001b"),
+       REGULATOR_SUPPLY("HPVDD", "0-001b"),
+       REGULATOR_SUPPLY("DBVDD", "0-001b"),
+       REGULATOR_SUPPLY("DCVDD", "0-001b"),
+};
+
+static struct regulator_init_data ek_avdd_reg_init_data = {
+       .constraints    = {
+               .name   = "3V3",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .consumer_supplies = ek_audio_consumer_supplies,
+       .num_consumer_supplies = ARRAY_SIZE(ek_audio_consumer_supplies),
+};
+
+static struct fixed_voltage_config ek_vdd_pdata = {
+       .supply_name    = "board-3V3",
+       .microvolts     = 3300000,
+       .gpio           = -EINVAL,
+       .enabled_at_boot = 0,
+       .init_data      = &ek_avdd_reg_init_data,
+};
+static struct platform_device ek_voltage_regulator = {
+       .name           = "reg-fixed-voltage",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &ek_vdd_pdata,
+       },
+};
+static void __init ek_add_regulators(void)
+{
+       platform_device_register(&ek_voltage_regulator);
+}
+#else
+static void __init ek_add_regulators(void) {}
+#endif
+
 static struct i2c_board_info __initdata ek_i2c_devices[] = {
        {
                I2C_BOARD_INFO("24c512", 0x50),
@@ -256,6 +299,8 @@ static void __init ek_board_init(void)
        ek_add_device_nand();
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
+       /* Regulators */
+       ek_add_regulators();
        /* MMC */
 #if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
        at91_add_device_mci(0, &ek_mmc_data);
index c11fd47aec5d464a9f228f19a9ac79097ebcaf46..6ea9808b8868d53a0c7cefd1926f921eadd82633 100644 (file)
@@ -27,6 +27,9 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/clk.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -269,6 +272,46 @@ static void __init ek_add_device_buttons(void)
 static void __init ek_add_device_buttons(void) {}
 #endif
 
+#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
+static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
+       REGULATOR_SUPPLY("AVDD", "0-001b"),
+       REGULATOR_SUPPLY("HPVDD", "0-001b"),
+       REGULATOR_SUPPLY("DBVDD", "0-001b"),
+       REGULATOR_SUPPLY("DCVDD", "0-001b"),
+};
+
+static struct regulator_init_data ek_avdd_reg_init_data = {
+       .constraints    = {
+               .name   = "3V3",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .consumer_supplies = ek_audio_consumer_supplies,
+       .num_consumer_supplies = ARRAY_SIZE(ek_audio_consumer_supplies),
+};
+
+static struct fixed_voltage_config ek_vdd_pdata = {
+       .supply_name    = "board-3V3",
+       .microvolts     = 3300000,
+       .gpio           = -EINVAL,
+       .enabled_at_boot = 0,
+       .init_data      = &ek_avdd_reg_init_data,
+};
+static struct platform_device ek_voltage_regulator = {
+       .name           = "reg-fixed-voltage",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &ek_vdd_pdata,
+       },
+};
+static void __init ek_add_regulators(void)
+{
+       platform_device_register(&ek_voltage_regulator);
+}
+#else
+static void __init ek_add_regulators(void) {}
+#endif
+
 
 static struct i2c_board_info __initdata ek_i2c_devices[] = {
         {
@@ -294,6 +337,8 @@ static void __init ek_board_init(void)
        ek_add_device_nand();
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
+       /* Regulators */
+       ek_add_regulators();
        /* MMC */
        at91_add_device_mmc(0, &ek_mmc_data);
        /* I2C */
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
new file mode 100644 (file)
index 0000000..2c08ae4
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-at91/board-snapper9260.c
+ *
+ *  Copyright (C) 2010 Bluewater System Ltd
+ *
+ * Author: Andre Renaud <andre@bluewatersys.com>
+ * Author: Ryan Mallon  <ryan@bluewatersys.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/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+#define SNAPPER9260_IO_EXP_GPIO(x)     (NR_BUILTIN_GPIO + (x))
+
+static void __init snapper9260_map_io(void)
+{
+       at91sam9260_initialize(18432000);
+
+       /* Debug on ttyS0 */
+       at91_register_uart(0, 0, 0);
+       at91_set_serial_console(0);
+
+       at91_register_uart(AT91SAM9260_ID_US0, 1,
+                          ATMEL_UART_CTS | ATMEL_UART_RTS);
+       at91_register_uart(AT91SAM9260_ID_US1, 2,
+                          ATMEL_UART_CTS | ATMEL_UART_RTS);
+       at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+}
+
+static void __init snapper9260_init_irq(void)
+{
+       at91sam9260_init_interrupts(NULL);
+}
+
+static struct at91_usbh_data __initdata snapper9260_usbh_data = {
+       .ports          = 2,
+};
+
+static struct at91_udc_data __initdata snapper9260_udc_data = {
+       .vbus_pin               = SNAPPER9260_IO_EXP_GPIO(5),
+       .vbus_active_low        = 1,
+       .vbus_polled            = 1,
+};
+
+static struct at91_eth_data snapper9260_macb_data = {
+       .is_rmii        = 1,
+};
+
+static struct mtd_partition __initdata snapper9260_nand_partitions[] = {
+       {
+               .name   = "Preboot",
+               .offset = 0,
+               .size   = SZ_128K,
+       },
+       {
+               .name   = "Bootloader",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = SZ_256K,
+       },
+       {
+               .name   = "Environment",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = SZ_128K,
+       },
+       {
+               .name   = "Kernel",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = SZ_4M,
+       },
+       {
+               .name   = "Filesystem",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct mtd_partition * __init
+snapper9260_nand_partition_info(int size, int *num_partitions)
+{
+       *num_partitions = ARRAY_SIZE(snapper9260_nand_partitions);
+       return snapper9260_nand_partitions;
+}
+
+static struct atmel_nand_data __initdata snapper9260_nand_data = {
+       .ale            = 21,
+       .cle            = 22,
+       .rdy_pin        = AT91_PIN_PC13,
+       .partition_info = snapper9260_nand_partition_info,
+       .bus_width_16   = 0,
+};
+
+static struct sam9_smc_config __initdata snapper9260_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 0,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 0,
+
+       .ncs_read_pulse         = 5,
+       .nrd_pulse              = 2,
+       .ncs_write_pulse        = 5,
+       .nwe_pulse              = 2,
+
+       .read_cycle             = 7,
+       .write_cycle            = 7,
+
+       .mode                   = (AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+                                  AT91_SMC_EXNWMODE_DISABLE),
+       .tdf_cycles             = 1,
+};
+
+static struct pca953x_platform_data snapper9260_io_expander_data = {
+       .gpio_base              = SNAPPER9260_IO_EXP_GPIO(0),
+};
+
+static struct i2c_board_info __initdata snapper9260_i2c_devices[] = {
+       {
+               /* IO expander */
+               I2C_BOARD_INFO("max7312", 0x28),
+               .platform_data = &snapper9260_io_expander_data,
+       },
+       {
+               /* Audio codec */
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       },
+       {
+               /* RTC */
+               I2C_BOARD_INFO("isl1208", 0x6f),
+       },
+};
+
+static void __init snapper9260_add_device_nand(void)
+{
+       at91_set_A_periph(AT91_PIN_PC14, 0);
+       sam9_smc_configure(3, &snapper9260_nand_smc_config);
+       at91_add_device_nand(&snapper9260_nand_data);
+}
+
+static void __init snapper9260_board_init(void)
+{
+       at91_add_device_i2c(snapper9260_i2c_devices,
+                           ARRAY_SIZE(snapper9260_i2c_devices));
+       at91_add_device_serial();
+       at91_add_device_usbh(&snapper9260_usbh_data);
+       at91_add_device_udc(&snapper9260_udc_data);
+       at91_add_device_eth(&snapper9260_macb_data);
+       at91_add_device_ssc(AT91SAM9260_ID_SSC, (ATMEL_SSC_TF | ATMEL_SSC_TK |
+                                                ATMEL_SSC_TD | ATMEL_SSC_RD));
+       snapper9260_add_device_nand();
+}
+
+MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
+       .phys_io        = AT91_BASE_SYS,
+       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = snapper9260_map_io,
+       .init_irq       = snapper9260_init_irq,
+       .init_machine   = snapper9260_board_init,
+MACHINE_END
+
+
index d8c1ededaa75aea4ab8835ade94c2dda544068f7..9c6af97374851a72d2481a0fc4b03ba64781eff8 100644 (file)
@@ -84,7 +84,7 @@
  */
 #define AT91_ECC       (0xffffe200 - AT91_BASE_SYS)
 #define AT91_BCRAMC    (0xffffe400 - AT91_BASE_SYS)
-#define AT91_DDRSDRC   (0xffffe600 - AT91_BASE_SYS)
+#define AT91_DDRSDRC0  (0xffffe600 - AT91_BASE_SYS)
 #define AT91_SMC       (0xffffe800 - AT91_BASE_SYS)
 #define AT91_MATRIX    (0xffffea00 - AT91_BASE_SYS)
 #define AT91_CCFG      (0xffffeb10 - AT91_BASE_SYS)
index 1499b1cbffddbe6c3f0ff3d70617d2314d574ab4..976f4a6c33532e85e6a8053df737cf638c820827 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef AT91CAP9_DDRSDR_H
 #define AT91CAP9_DDRSDR_H
 
-#define AT91_DDRSDRC_MR                (AT91_DDRSDRC + 0x00)   /* Mode Register */
+#define AT91_DDRSDRC_MR                0x00    /* Mode Register */
 #define                AT91_DDRSDRC_MODE       (0xf << 0)              /* Command Mode */
 #define                        AT91_DDRSDRC_MODE_NORMAL                0
 #define                        AT91_DDRSDRC_MODE_NOP           1
 #define                        AT91_DDRSDRC_MODE_EXT_LMR       5
 #define                        AT91_DDRSDRC_MODE_DEEP          6
 
-#define AT91_DDRSDRC_RTR       (AT91_DDRSDRC + 0x04)   /* Refresh Timer Register */
+#define AT91_DDRSDRC_RTR       0x04    /* Refresh Timer Register */
 #define                AT91_DDRSDRC_COUNT      (0xfff << 0)            /* Refresh Timer Counter */
 
-#define AT91_DDRSDRC_CR                (AT91_DDRSDRC + 0x08)   /* Configuration Register */
+#define AT91_DDRSDRC_CR                0x08    /* Configuration Register */
 #define                AT91_DDRSDRC_NC         (3 << 0)                /* Number of Column Bits */
 #define                        AT91_DDRSDRC_NC_SDR8    (0 << 0)
 #define                        AT91_DDRSDRC_NC_SDR9    (1 << 0)
@@ -49,7 +49,7 @@
 #define                AT91_DDRSDRC_DLL        (1 << 7)                /* Reset DLL */
 #define                AT91_DDRSDRC_DICDS      (1 << 8)                /* Output impedance control */
 
-#define AT91_DDRSDRC_T0PR      (AT91_DDRSDRC + 0x0C)   /* Timing 0 Register */
+#define AT91_DDRSDRC_T0PR      0x0C    /* Timing 0 Register */
 #define                AT91_DDRSDRC_TRAS       (0xf <<  0)             /* Active to Precharge delay */
 #define                AT91_DDRSDRC_TRCD       (0xf <<  4)             /* Row to Column delay */
 #define                AT91_DDRSDRC_TWR        (0xf <<  8)             /* Write recovery delay */
 #define                AT91_DDRSDRC_TWTR       (1   << 24)             /* Internal Write to Read delay */
 #define                AT91_DDRSDRC_TMRD       (0xf << 28)             /* Load mode to active/refresh delay */
 
-#define AT91_DDRSDRC_T1PR      (AT91_DDRSDRC + 0x10)   /* Timing 1 Register */
+#define AT91_DDRSDRC_T1PR      0x10    /* Timing 1 Register */
 #define                AT91_DDRSDRC_TRFC       (0x1f << 0)             /* Row Cycle Delay */
 #define                AT91_DDRSDRC_TXSNR      (0xff << 8)             /* Exit self-refresh to non-read */
 #define                AT91_DDRSDRC_TXSRD      (0xff << 16)            /* Exit self-refresh to read */
 #define                AT91_DDRSDRC_TXP        (0xf  << 24)            /* Exit power-down delay */
 
-#define AT91_DDRSDRC_LPR       (AT91_DDRSDRC + 0x18)   /* Low Power Register */
+#define AT91_DDRSDRC_LPR       0x18    /* Low Power Register */
 #define                AT91_DDRSDRC_LPCB               (3 << 0)        /* Low-power Configurations */
 #define                        AT91_DDRSDRC_LPCB_DISABLE               0
 #define                        AT91_DDRSDRC_LPCB_SELF_REFRESH          1
 #define                        AT91_DDRSDRC_TIMEOUT_64_CLK_CYCLES      (1 << 12)
 #define                        AT91_DDRSDRC_TIMEOUT_128_CLK_CYCLES     (2 << 12)
 
-#define AT91_DDRSDRC_MDR       (AT91_DDRSDRC + 0x1C)   /* Memory Device Register */
+#define AT91_DDRSDRC_MDR       0x1C    /* Memory Device Register */
 #define                AT91_DDRSDRC_MD         (3 << 0)                /* Memory Device Type */
 #define                        AT91_DDRSDRC_MD_SDR             0
 #define                        AT91_DDRSDRC_MD_LOW_POWER_SDR   1
 #define                        AT91_DDRSDRC_MD_DDR             2
 #define                        AT91_DDRSDRC_MD_LOW_POWER_DDR   3
 
-#define AT91_DDRSDRC_DLLR      (AT91_DDRSDRC + 0x20)   /* DLL Information Register */
+#define AT91_DDRSDRC_DLLR      0x20    /* DLL Information Register */
 #define                AT91_DDRSDRC_MDINC      (1 << 0)                /* Master Delay increment */
 #define                AT91_DDRSDRC_MDDEC      (1 << 1)                /* Master Delay decrement */
 #define                AT91_DDRSDRC_MDOVF      (1 << 2)                /* Master Delay Overflow */
 #define                AT91_DDRSDRC_SDVAL      (0xff << 16)            /* Slave Delay value */
 #define                AT91_DDRSDRC_SDCVAL     (0xff << 24)            /* Slave Delay Correction value */
 
+/* Register access macros */
+#define at91_ramc_read(num, reg) \
+       at91_sys_read(AT91_DDRSDRC##num + reg)
+#define at91_ramc_write(num, reg, value) \
+       at91_sys_write(AT91_DDRSDRC##num + reg, value)
+
 
 #endif
index 43c396b9b4cb8cc1ceedf44bf24fe62ff225c880..4e79036d3b801849ea8f547e6dd6fdf8b16d894e 100644 (file)
@@ -84,7 +84,7 @@
  * System Peripherals (offset from AT91_BASE_SYS)
  */
 #define AT91_ECC       (0xffffe800 - AT91_BASE_SYS)
-#define AT91_SDRAMC    (0xffffea00 - AT91_BASE_SYS)
+#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
 #define AT91_SMC       (0xffffec00 - AT91_BASE_SYS)
 #define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
 #define AT91_CCFG      (0xffffef10 - AT91_BASE_SYS)
index 87de8be17484be6966c7ee02bcf4a94620932e63..2b561851812952fe60e8b44fa1d44641fcdd81bc 100644 (file)
@@ -68,7 +68,7 @@
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
  */
-#define AT91_SDRAMC    (0xffffea00 - AT91_BASE_SYS)
+#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
 #define AT91_SMC       (0xffffec00 - AT91_BASE_SYS)
 #define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
 #define AT91_AIC       (0xfffff000 - AT91_BASE_SYS)
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h b/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h
new file mode 100644 (file)
index 0000000..d27b15b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Header file for the Atmel DDR/SDR SDRAM Controller
+ *
+ * Copyright (C) 2010 Atmel Corporation
+ *     Nicolas Ferre <nicolas.ferre@atmel.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 AT91SAM9_DDRSDR_H
+#define AT91SAM9_DDRSDR_H
+
+#define AT91_DDRSDRC_MR                0x00    /* Mode Register */
+#define                AT91_DDRSDRC_MODE       (0x7 << 0)              /* Command Mode */
+#define                        AT91_DDRSDRC_MODE_NORMAL        0
+#define                        AT91_DDRSDRC_MODE_NOP           1
+#define                        AT91_DDRSDRC_MODE_PRECHARGE     2
+#define                        AT91_DDRSDRC_MODE_LMR           3
+#define                        AT91_DDRSDRC_MODE_REFRESH       4
+#define                        AT91_DDRSDRC_MODE_EXT_LMR       5
+#define                        AT91_DDRSDRC_MODE_DEEP          6
+
+#define AT91_DDRSDRC_RTR       0x04    /* Refresh Timer Register */
+#define                AT91_DDRSDRC_COUNT      (0xfff << 0)            /* Refresh Timer Counter */
+
+#define AT91_DDRSDRC_CR                0x08    /* Configuration Register */
+#define                AT91_DDRSDRC_NC         (3 << 0)                /* Number of Column Bits */
+#define                        AT91_DDRSDRC_NC_SDR8    (0 << 0)
+#define                        AT91_DDRSDRC_NC_SDR9    (1 << 0)
+#define                        AT91_DDRSDRC_NC_SDR10   (2 << 0)
+#define                        AT91_DDRSDRC_NC_SDR11   (3 << 0)
+#define                        AT91_DDRSDRC_NC_DDR9    (0 << 0)
+#define                        AT91_DDRSDRC_NC_DDR10   (1 << 0)
+#define                        AT91_DDRSDRC_NC_DDR11   (2 << 0)
+#define                        AT91_DDRSDRC_NC_DDR12   (3 << 0)
+#define                AT91_DDRSDRC_NR         (3 << 2)                /* Number of Row Bits */
+#define                        AT91_DDRSDRC_NR_11      (0 << 2)
+#define                        AT91_DDRSDRC_NR_12      (1 << 2)
+#define                        AT91_DDRSDRC_NR_13      (2 << 2)
+#define                        AT91_DDRSDRC_NR_14      (3 << 2)
+#define                AT91_DDRSDRC_CAS        (7 << 4)                /* CAS Latency */
+#define                        AT91_DDRSDRC_CAS_2      (2 << 4)
+#define                        AT91_DDRSDRC_CAS_3      (3 << 4)
+#define                        AT91_DDRSDRC_CAS_25     (6 << 4)
+#define                AT91_DDRSDRC_RST_DLL    (1 << 7)                /* Reset DLL */
+#define                AT91_DDRSDRC_DICDS      (1 << 8)                /* Output impedance control */
+#define                AT91_DDRSDRC_DIS_DLL    (1 << 9)                /* Disable DLL */
+#define                AT91_DDRSDRC_OCD        (1 << 12)               /* Off-Chip Driver */
+#define                AT91_DDRSDRC_DQMS       (1 << 16)               /* Mask Data is Shared */
+#define                AT91_DDRSDRC_ACTBST     (1 << 18)               /* Active Bank X to Burst Stop Read Access Bank Y */
+
+#define AT91_DDRSDRC_T0PR      0x0C    /* Timing 0 Register */
+#define                AT91_DDRSDRC_TRAS       (0xf <<  0)             /* Active to Precharge delay */
+#define                AT91_DDRSDRC_TRCD       (0xf <<  4)             /* Row to Column delay */
+#define                AT91_DDRSDRC_TWR        (0xf <<  8)             /* Write recovery delay */
+#define                AT91_DDRSDRC_TRC        (0xf << 12)             /* Row cycle delay */
+#define                AT91_DDRSDRC_TRP        (0xf << 16)             /* Row precharge delay */
+#define                AT91_DDRSDRC_TRRD       (0xf << 20)             /* Active BankA to BankB */
+#define                AT91_DDRSDRC_TWTR       (0x7 << 24)             /* Internal Write to Read delay */
+#define                AT91_DDRSDRC_RED_WRRD   (0x1 << 27)             /* Reduce Write to Read Delay */
+#define                AT91_DDRSDRC_TMRD       (0xf << 28)             /* Load mode to active/refresh delay */
+
+#define AT91_DDRSDRC_T1PR      0x10    /* Timing 1 Register */
+#define                AT91_DDRSDRC_TRFC       (0x1f << 0)             /* Row Cycle Delay */
+#define                AT91_DDRSDRC_TXSNR      (0xff << 8)             /* Exit self-refresh to non-read */
+#define                AT91_DDRSDRC_TXSRD      (0xff << 16)            /* Exit self-refresh to read */
+#define                AT91_DDRSDRC_TXP        (0xf  << 24)            /* Exit power-down delay */
+
+#define AT91_DDRSDRC_T2PR      0x14    /* Timing 2 Register */
+#define                AT91_DDRSDRC_TXARD      (0xf  << 0)             /* Exit active power down delay to read command in mode "Fast Exit" */
+#define                AT91_DDRSDRC_TXARDS     (0xf  << 4)             /* Exit active power down delay to read command in mode "Slow Exit" */
+#define                AT91_DDRSDRC_TRPA       (0xf  << 8)             /* Row Precharge All delay */
+#define                AT91_DDRSDRC_TRTP       (0x7  << 12)            /* Read to Precharge delay */
+
+#define AT91_DDRSDRC_LPR       0x1C    /* Low Power Register */
+#define                AT91_DDRSDRC_LPCB       (3 << 0)                /* Low-power Configurations */
+#define                        AT91_DDRSDRC_LPCB_DISABLE               0
+#define                        AT91_DDRSDRC_LPCB_SELF_REFRESH          1
+#define                        AT91_DDRSDRC_LPCB_POWER_DOWN            2
+#define                        AT91_DDRSDRC_LPCB_DEEP_POWER_DOWN       3
+#define                AT91_DDRSDRC_CLKFR      (1 << 2)        /* Clock Frozen */
+#define                AT91_DDRSDRC_PASR       (7 << 4)        /* Partial Array Self Refresh */
+#define                AT91_DDRSDRC_TCSR       (3 << 8)        /* Temperature Compensated Self Refresh */
+#define                AT91_DDRSDRC_DS         (3 << 10)       /* Drive Strength */
+#define                AT91_DDRSDRC_TIMEOUT    (3 << 12)       /* Time to define when Low Power Mode is enabled */
+#define                        AT91_DDRSDRC_TIMEOUT_0_CLK_CYCLES       (0 << 12)
+#define                        AT91_DDRSDRC_TIMEOUT_64_CLK_CYCLES      (1 << 12)
+#define                        AT91_DDRSDRC_TIMEOUT_128_CLK_CYCLES     (2 << 12)
+#define                AT91_DDRSDRC_APDE       (1 << 16)        /* Active power down exit time */
+#define                AT91_DDRSDRC_UPD_MR     (3 << 20)        /* Update load mode register and extended mode register */
+
+#define AT91_DDRSDRC_MDR       0x20    /* Memory Device Register */
+#define                AT91_DDRSDRC_MD         (3 << 0)                /* Memory Device Type */
+#define                        AT91_DDRSDRC_MD_SDR             0
+#define                        AT91_DDRSDRC_MD_LOW_POWER_SDR   1
+#define                        AT91_DDRSDRC_MD_LOW_POWER_DDR   3
+#define                        AT91_DDRSDRC_MD_DDR2            6
+#define                AT91_DDRSDRC_DBW        (1 << 4)                /* Data Bus Width */
+#define                        AT91_DDRSDRC_DBW_32BITS         (0 <<  4)
+#define                        AT91_DDRSDRC_DBW_16BITS         (1 <<  4)
+
+#define AT91_DDRSDRC_DLL       0x24    /* DLL Information Register */
+#define                AT91_DDRSDRC_MDINC      (1 << 0)                /* Master Delay increment */
+#define                AT91_DDRSDRC_MDDEC      (1 << 1)                /* Master Delay decrement */
+#define                AT91_DDRSDRC_MDOVF      (1 << 2)                /* Master Delay Overflow */
+#define                AT91_DDRSDRC_MDVAL      (0xff <<  8)            /* Master Delay value */
+
+#define AT91_DDRSDRC_HS                0x2C    /* High Speed Register */
+#define                AT91_DDRSDRC_DIS_ATCP_RD        (1 << 2)        /* Anticip read access is disabled */
+
+#define AT91_DDRSDRC_DELAY(n)  (0x30 + (0x4 * (n)))    /* Delay I/O Register n */
+
+#define AT91_DDRSDRC_WPMR      0xE4    /* Write Protect Mode Register */
+#define                AT91_DDRSDRC_WP         (1 << 0)                /* Write protect enable */
+#define                AT91_DDRSDRC_WPKEY      (0xffffff << 8)         /* Write protect key */
+#define                AT91_DDRSDRC_KEY        (0x444452 << 8)         /* Write protect key = "DDR" */
+
+#define AT91_DDRSDRC_WPSR      0xE8    /* Write Protect Status Register */
+#define                AT91_DDRSDRC_WPVS       (1 << 0)                /* Write protect violation status */
+#define                AT91_DDRSDRC_WPVSRC     (0xffff << 8)           /* Write protect violation source */
+
+/* Register access macros */
+#define at91_ramc_read(num, reg) \
+       at91_sys_read(AT91_DDRSDRC##num + reg)
+#define at91_ramc_write(num, reg, value) \
+       at91_sys_write(AT91_DDRSDRC##num + reg, value)
+
+#endif
index b7260389f7cac2a51937143c10e55e3e75ee8aa9..100f5a592926356db536780996a7796ff6856e91 100644 (file)
@@ -17,7 +17,7 @@
 #define AT91SAM9_SDRAMC_H
 
 /* SDRAM Controller (SDRAMC) registers */
-#define AT91_SDRAMC_MR         (AT91_SDRAMC + 0x00)    /* SDRAM Controller Mode Register */
+#define AT91_SDRAMC_MR         0x00    /* SDRAM Controller Mode Register */
 #define                AT91_SDRAMC_MODE        (0xf << 0)              /* Command Mode */
 #define                        AT91_SDRAMC_MODE_NORMAL         0
 #define                        AT91_SDRAMC_MODE_NOP            1
 #define                        AT91_SDRAMC_MODE_EXT_LMR        5
 #define                        AT91_SDRAMC_MODE_DEEP           6
 
-#define AT91_SDRAMC_TR         (AT91_SDRAMC + 0x04)    /* SDRAM Controller Refresh Timer Register */
+#define AT91_SDRAMC_TR         0x04    /* SDRAM Controller Refresh Timer Register */
 #define                AT91_SDRAMC_COUNT       (0xfff << 0)            /* Refresh Timer Counter */
 
-#define AT91_SDRAMC_CR         (AT91_SDRAMC + 0x08)    /* SDRAM Controller Configuration Register */
+#define AT91_SDRAMC_CR         0x08    /* SDRAM Controller Configuration Register */
 #define                AT91_SDRAMC_NC          (3 << 0)                /* Number of Column Bits */
 #define                        AT91_SDRAMC_NC_8        (0 << 0)
 #define                        AT91_SDRAMC_NC_9        (1 << 0)
@@ -57,7 +57,7 @@
 #define                AT91_SDRAMC_TRAS        (0xf << 24)             /* Active to Precharge Delay */
 #define                AT91_SDRAMC_TXSR        (0xf << 28)             /* Exit Self Refresh to Active Delay */
 
-#define AT91_SDRAMC_LPR                (AT91_SDRAMC + 0x10)    /* SDRAM Controller Low Power Register */
+#define AT91_SDRAMC_LPR                0x10    /* SDRAM Controller Low Power Register */
 #define                AT91_SDRAMC_LPCB                (3 << 0)        /* Low-power Configurations */
 #define                        AT91_SDRAMC_LPCB_DISABLE                0
 #define                        AT91_SDRAMC_LPCB_SELF_REFRESH           1
 #define                        AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES       (1 << 12)
 #define                        AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES      (2 << 12)
 
-#define AT91_SDRAMC_IER                (AT91_SDRAMC + 0x14)    /* SDRAM Controller Interrupt Enable Register */
-#define AT91_SDRAMC_IDR                (AT91_SDRAMC + 0x18)    /* SDRAM Controller Interrupt Disable Register */
-#define AT91_SDRAMC_IMR                (AT91_SDRAMC + 0x1C)    /* SDRAM Controller Interrupt Mask Register */
-#define AT91_SDRAMC_ISR                (AT91_SDRAMC + 0x20)    /* SDRAM Controller Interrupt Status Register */
+#define AT91_SDRAMC_IER                0x14    /* SDRAM Controller Interrupt Enable Register */
+#define AT91_SDRAMC_IDR                0x18    /* SDRAM Controller Interrupt Disable Register */
+#define AT91_SDRAMC_IMR                0x1C    /* SDRAM Controller Interrupt Mask Register */
+#define AT91_SDRAMC_ISR                0x20    /* SDRAM Controller Interrupt Status Register */
 #define                AT91_SDRAMC_RES         (1 << 0)                /* Refresh Error Status */
 
-#define AT91_SDRAMC_MDR                (AT91_SDRAMC + 0x24)    /* SDRAM Memory Device Register */
+#define AT91_SDRAMC_MDR                0x24    /* SDRAM Memory Device Register */
 #define                AT91_SDRAMC_MD          (3 << 0)                /* Memory Device Type */
 #define                        AT91_SDRAMC_MD_SDRAM            0
 #define                        AT91_SDRAMC_MD_LOW_POWER_SDRAM  1
 
+/* Register access macros */
+#define at91_ramc_read(num, reg) \
+       at91_sys_read(AT91_SDRAMC##num + reg)
+#define at91_ramc_write(num, reg, value) \
+       at91_sys_write(AT91_SDRAMC##num + reg, value)
 
 #endif
index fc2de6c09c86a67c21073e405144ad17d94f8f64..87ba8517ad98291a12749853cfc7379e021c4997 100644 (file)
@@ -74,7 +74,7 @@
  */
 #define AT91_DMA       (0xffffe600 - AT91_BASE_SYS)
 #define AT91_ECC       (0xffffe800 - AT91_BASE_SYS)
-#define AT91_SDRAMC    (0xffffea00 - AT91_BASE_SYS)
+#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
 #define AT91_SMC       (0xffffec00 - AT91_BASE_SYS)
 #define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
 #define AT91_CCFG      (0xffffef10 - AT91_BASE_SYS)
index df2ed848c9f89b0e9f2e0bb3ee6a7c8d0fd631d5..58528aa9c8a86ddea8286cfb9ebdac7e26ed6942 100644 (file)
@@ -44,6 +44,8 @@
  /* USB Device */
 struct at91_udc_data {
        u8      vbus_pin;               /* high == host powering us */
+       u8      vbus_active_low;        /* vbus polarity */
+       u8      vbus_polled;            /* Use polling, not interrupt */
        u8      pullup_pin;             /* active == D+ pulled up */
        u8      pullup_active_low;      /* true == pullup_pin is active low */
 };
index 833659d1200ac057faff56ccd567de4ad718e09b..3bef931d0b1c915b5de540ee860dcf37cf27cba6 100644 (file)
@@ -52,6 +52,7 @@ static inline unsigned long at91_cpu_fully_identify(void)
 
 #define ARCH_EXID_AT91SAM9M11  0x00000001
 #define ARCH_EXID_AT91SAM9M10  0x00000002
+#define ARCH_EXID_AT91SAM9G46  0x00000003
 #define ARCH_EXID_AT91SAM9G45  0x00000004
 
 static inline unsigned long at91_exid_identify(void)
@@ -128,9 +129,18 @@ static inline unsigned long at91cap9_rev_identify(void)
 #ifdef CONFIG_ARCH_AT91SAM9G45
 #define cpu_is_at91sam9g45()   (at91_cpu_identify() == ARCH_ID_AT91SAM9G45)
 #define cpu_is_at91sam9g45es() (at91_cpu_fully_identify() == ARCH_ID_AT91SAM9G45ES)
+#define cpu_is_at91sam9m10()    (cpu_is_at91sam9g45() && \
+                                (at91_exid_identify() == ARCH_EXID_AT91SAM9M10))
+#define cpu_is_at91sam9m46()    (cpu_is_at91sam9g45() && \
+                                (at91_exid_identify() == ARCH_EXID_AT91SAM9G46))
+#define cpu_is_at91sam9m11()    (cpu_is_at91sam9g45() && \
+                                (at91_exid_identify() == ARCH_EXID_AT91SAM9M11))
 #else
 #define cpu_is_at91sam9g45()   (0)
 #define cpu_is_at91sam9g45es() (0)
+#define cpu_is_at91sam9m10()   (0)
+#define cpu_is_at91sam9g46()   (0)
+#define cpu_is_at91sam9m11()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91CAP9
index 04c91e31c9c5be8a7c20ca5a31b6ebef99963f89..bfdd8ab26dc8a2399a379058df2e9a04f41c2888 100644 (file)
@@ -19,6 +19,7 @@
 #define PIN_BASE               NR_AIC_IRQS
 
 #define MAX_GPIO_BANKS         5
+#define NR_BUILTIN_GPIO                (PIN_BASE + (MAX_GPIO_BANKS * 32))
 
 /* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */
 
index 08322c44df1a98d287c0247321158de4d41bb99c..8c87d0c1b8f8b9b9dc0383bff155798454a6460f 100644 (file)
@@ -30,14 +30,50 @@ static inline u32 sdram_selfrefresh_enable(void)
 {
        u32 saved_lpr, lpr;
 
-       saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR);
+       saved_lpr = at91_ramc_read(0, AT91_DDRSDRC_LPR);
 
        lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
-       at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
+       at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
        return saved_lpr;
 }
 
-#define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr)
+#define sdram_selfrefresh_disable(saved_lpr)   at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr)
+
+#elif defined(CONFIG_ARCH_AT91SAM9G45)
+#include <mach/at91sam9_ddrsdr.h>
+
+/* We manage both DDRAM/SDRAM controllers, we need more than one value to
+ * remember.
+ */
+static u32 saved_lpr1;
+
+static inline u32 sdram_selfrefresh_enable(void)
+{
+       /* Those tow values allow us to delay self-refresh activation
+        * to the maximum. */
+       u32 lpr0, lpr1;
+       u32 saved_lpr0;
+
+       saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
+       lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
+       lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
+
+       saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
+       lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
+       lpr0 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
+
+       /* self-refresh mode now */
+       at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
+       at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
+
+       return saved_lpr0;
+}
+
+#define sdram_selfrefresh_disable(saved_lpr0)  \
+       do { \
+               at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
+               at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
+       } while (0)
 
 #else
 #include <mach/at91sam9_sdramc.h>
@@ -47,7 +83,6 @@ static inline u32 sdram_selfrefresh_enable(void)
  * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
  * handle those cases both here and in the Suspend-To-RAM support.
  */
-#define        AT91_SDRAMC     AT91_SDRAMC0
 #warning Assuming EB1 SDRAM controller is *NOT* used
 #endif
 
@@ -55,13 +90,13 @@ static inline u32 sdram_selfrefresh_enable(void)
 {
        u32 saved_lpr, lpr;
 
-       saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
+       saved_lpr = at91_ramc_read(0, AT91_SDRAMC_LPR);
 
        lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
-       at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
+       at91_ramc_write(0, AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
        return saved_lpr;
 }
 
-#define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
+#define sdram_selfrefresh_disable(saved_lpr)   at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr)
 
 #endif
index 9c5b48e68a71343e26f2f17c4856886fc0509373..b6b00a1f612546eb463036214455336381560e37 100644 (file)
 #include <mach/hardware.h>
 #include <mach/at91_pmc.h>
 
-#ifdef CONFIG_ARCH_AT91RM9200
+#if defined(CONFIG_ARCH_AT91RM9200)
 #include <mach/at91rm9200_mc.h>
 #elif defined(CONFIG_ARCH_AT91CAP9)
 #include <mach/at91cap9_ddrsdr.h>
+#elif defined(CONFIG_ARCH_AT91SAM9G45)
+#include <mach/at91sam9_ddrsdr.h>
 #else
 #include <mach/at91sam9_sdramc.h>
 #endif
@@ -30,7 +32,6 @@
  * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
  * handle those cases both here and in the Suspend-To-RAM support.
  */
-#define AT91_SDRAMC    AT91_SDRAMC0
 #warning Assuming EB1 SDRAM controller is *NOT* used
 #endif
 
@@ -113,12 +114,14 @@ ENTRY(at91_slow_clock)
        /*
         * Register usage:
         *  R1 = Base address of AT91_PMC
-        *  R2 = Base address of AT91_SDRAMC (or AT91_SYS on AT91RM9200)
+        *  R2 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
         *  R3 = temporary register
         *  R4 = temporary register
+        *  R5 = Base address of second RAM Controller or 0 if not present
         */
        ldr     r1, .at91_va_base_pmc
        ldr     r2, .at91_va_base_sdramc
+       ldr     r5, .at91_va_base_ramc1
 
        /* Drain write buffer */
        mcr     p15, 0, r0, c7, c10, 4
@@ -127,20 +130,33 @@ ENTRY(at91_slow_clock)
        /* Put SDRAM in self-refresh mode */
        mov     r3, #1
        str     r3, [r2, #AT91_SDRAMC_SRR]
-#elif defined(CONFIG_ARCH_AT91CAP9)
-       /* Enable SDRAM self-refresh mode */
-       ldr     r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC]
-       str     r3, .saved_sam9_lpr
+#elif defined(CONFIG_ARCH_AT91CAP9) \
+       || defined(CONFIG_ARCH_AT91SAM9G45)
 
-       mov     r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC]
+       /* prepare for DDRAM self-refresh mode */
+       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
+       str     r3, .saved_sam9_lpr
+       bic     r3, #AT91_DDRSDRC_LPCB
+       orr     r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+
+       /* figure out if we use the second ram controller */
+       cmp     r5, #0
+       ldrne   r4, [r5, #AT91_DDRSDRC_LPR]
+       strne   r4, .saved_sam9_lpr1
+       bicne   r4, #AT91_DDRSDRC_LPCB
+       orrne   r4, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+
+       /* Enable DDRAM self-refresh mode */
+       str     r3, [r2, #AT91_DDRSDRC_LPR]
+       strne   r4, [r5, #AT91_DDRSDRC_LPR]
 #else
        /* Enable SDRAM self-refresh mode */
-       ldr     r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC]
+       ldr     r3, [r2, #AT91_SDRAMC_LPR]
        str     r3, .saved_sam9_lpr
 
-       mov     r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC]
+       bic     r3, #AT91_SDRAMC_LPCB
+       orr     r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
+       str     r3, [r2, #AT91_SDRAMC_LPR]
 #endif
 
        /* Save Master clock setting */
@@ -247,14 +263,21 @@ ENTRY(at91_slow_clock)
 
 #ifdef CONFIG_ARCH_AT91RM9200
        /* Do nothing - self-refresh is automatically disabled. */
-#elif defined(CONFIG_ARCH_AT91CAP9)
-       /* Restore LPR on AT91CAP9 */
+#elif defined(CONFIG_ARCH_AT91CAP9) \
+       || defined(CONFIG_ARCH_AT91SAM9G45)
+       /* Restore LPR on AT91 with DDRAM */
        ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC]
+       str     r3, [r2, #AT91_DDRSDRC_LPR]
+
+       /* if we use the second ram controller */
+       cmp     r5, #0
+       ldrne   r4, .saved_sam9_lpr1
+       strne   r4, [r5, #AT91_DDRSDRC_LPR]
+
 #else
-       /* Restore LPR on AT91SAM9 */
+       /* Restore LPR on AT91 with SDRAM */
        ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC]
+       str     r3, [r2, #AT91_SDRAMC_LPR]
 #endif
 
        /* Restore registers, and return */
@@ -273,18 +296,29 @@ ENTRY(at91_slow_clock)
 .saved_sam9_lpr:
        .word 0
 
+.saved_sam9_lpr1:
+       .word 0
+
 .at91_va_base_pmc:
        .word AT91_VA_BASE_SYS + AT91_PMC
 
 #ifdef CONFIG_ARCH_AT91RM9200
 .at91_va_base_sdramc:
        .word AT91_VA_BASE_SYS
-#elif defined(CONFIG_ARCH_AT91CAP9)
+#elif defined(CONFIG_ARCH_AT91CAP9) \
+       || defined(CONFIG_ARCH_AT91SAM9G45)
 .at91_va_base_sdramc:
-       .word AT91_VA_BASE_SYS + AT91_DDRSDRC
+       .word AT91_VA_BASE_SYS + AT91_DDRSDRC0
 #else
 .at91_va_base_sdramc:
-       .word AT91_VA_BASE_SYS + AT91_SDRAMC
+       .word AT91_VA_BASE_SYS + AT91_SDRAMC0
+#endif
+
+.at91_va_base_ramc1:
+#if defined(CONFIG_ARCH_AT91SAM9G45)
+       .word AT91_VA_BASE_SYS + AT91_DDRSDRC1
+#else
+       .word 0
 #endif
 
 ENTRY(at91_slow_clock_sz)
index 72e405df0fb07dd4b363153f149742875725f7ad..d3f959e92b2dd2ef15e129a3bd79e52801811efe 100644 (file)
@@ -91,14 +91,23 @@ static struct clk uart_clk = {
        .parent = &pll1_clk,
 };
 
+static struct clk dummy_apb_pclk = {
+       .name = "BUSCLK",
+       .type = CLK_TYPE_PRIMARY,
+       .mode = CLK_MODE_XTAL,
+};
+
 static struct clk_lookup lookups[] = {
-       {                       /* UART0 */
-        .dev_id = "uarta",
-        .clk = &uart_clk,
-        }, {                   /* UART1 */
-            .dev_id = "uartb",
-            .clk = &uart_clk,
-            }
+       {                       /* Bus clock */
+               .con_id = "apb_pclk",
+               .clk = &dummy_apb_pclk,
+       }, {                    /* UART0 */
+               .dev_id = "uarta",
+               .clk = &uart_clk,
+       }, {                    /* UART1 */
+               .dev_id = "uartb",
+               .clk = &uart_clk,
+       }
 };
 
 static struct amba_device *amba_devs[] __initdata = {
index dbaae5f746a1ced107faf56439c7f2bf71bc845c..eb34bd1251d491224f95216ca882070baa5933ce 100644 (file)
@@ -30,7 +30,6 @@ config ARCH_CLEP7312
 config ARCH_EDB7211
        bool "EDB7211"
        select ISA
-       select ARCH_DISCONTIGMEM_ENABLE
        select ARCH_SPARSEMEM_ENABLE
        select ARCH_SELECT_MEMORY_MODEL
        help
index 09fb57e452130d0766f4fe3eab0219138572ea13..3c3bf45039ff05f44c122adbc3bb1cceded613ab 100644 (file)
@@ -32,7 +32,6 @@ fixup_clep7312(struct machine_desc *desc, struct tag *tags,
        mi->nr_banks=1;
        mi->bank[0].start = 0xc0000000;
        mi->bank[0].size = 0x01000000;
-       mi->bank[0].node = 0;
 }
 
 
index dc81cc68595de96edd2f9e2679d1cd855bace03f..4a7a2322979a17c3dcb833bf44122f8af51bba8a 100644 (file)
@@ -18,6 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/init.h>
+#include <linux/memblock.h>
 #include <linux/types.h>
 #include <linux/string.h>
 
 
 extern void edb7211_map_io(void);
 
+/* Reserve screen memory region at the start of main system memory. */
+static void __init edb7211_reserve(void)
+{
+       memblock_reserve(PHYS_OFFSET, 0x00020000);
+}
+
 static void __init
 fixup_edb7211(struct machine_desc *desc, struct tag *tags,
              char **cmdline, struct meminfo *mi)
@@ -43,10 +50,8 @@ fixup_edb7211(struct machine_desc *desc, struct tag *tags,
         */
        mi->bank[0].start = 0xc0000000;
        mi->bank[0].size = 8*1024*1024;
-       mi->bank[0].node = 0;
        mi->bank[1].start = 0xc1000000;
        mi->bank[1].size = 8*1024*1024;
-       mi->bank[1].node = 1;
        mi->nr_banks = 2;
 }
 
@@ -57,6 +62,7 @@ MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
        .boot_params    = 0xc0020100,   /* 0xc0000000 - 0xc001ffff can be video RAM */
        .fixup          = fixup_edb7211,
        .map_io         = edb7211_map_io,
+       .reserve        = edb7211_reserve,
        .init_irq       = clps711x_init_irq,
        .timer          = &clps711x_timer,
 MACHINE_END
index 7430e4049d87b1ca789b372f2641c4088547c31c..a696099aa4f8f22ddd32e836b4bbb124acdc4ea0 100644 (file)
@@ -39,7 +39,6 @@ struct meminfo memmap = {
                {
                        .start  = 0xC0000000,
                        .size   = 0x01000000,
-                       .node   = 0
                },
        },
 };
index f70d52be48a2a61c88b7276a830b7b3abf17aee5..f45c8e892cb5a0ae9cdf0c9cd2c78c2dfa61bb07 100644 (file)
@@ -20,7 +20,6 @@
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
-
 /*
  * Physical DRAM offset.
  */
@@ -72,7 +71,6 @@
  *     node 2:  0xd0000000 - 0xd7ffffff
  *     node 3:  0xd8000000 - 0xdfffffff
  */
-#define NODE_MEM_SIZE_BITS     24
 #define SECTION_SIZE_BITS      24
 #define MAX_PHYSMEM_BITS       32
 
index 427507a2d696255449456da00763562056bd731e..11033f1c2e23b82b52d96569fb4932be6a1a11c0 100644 (file)
@@ -1,2 +1,3 @@
-obj-$(CONFIG_ARCH_CNS3XXX)             += core.o pm.o
+obj-$(CONFIG_ARCH_CNS3XXX)             += core.o pm.o devices.o
+obj-$(CONFIG_PCI)                      += pcie.o
 obj-$(CONFIG_MACH_CNS3420VB)           += cns3420vb.o
index 2e30c8288740b2a24752cdfe565a7e2bef5e77ca..9df8391fd78ac9ebfbb33425261ff9c631db79b1 100644 (file)
@@ -32,6 +32,7 @@
 #include <mach/cns3xxx.h>
 #include <mach/irqs.h>
 #include "core.h"
+#include "devices.h"
 
 /*
  * NOR Flash
@@ -117,6 +118,9 @@ static void __init cns3420_init(void)
 {
        platform_add_devices(cns3420_pdevs, ARRAY_SIZE(cns3420_pdevs));
 
+       cns3xxx_ahci_init();
+       cns3xxx_sdhci_init();
+
        pm_power_off = cns3xxx_power_off;
 }
 
diff --git a/arch/arm/mach-cns3xxx/devices.c b/arch/arm/mach-cns3xxx/devices.c
new file mode 100644 (file)
index 0000000..50b4d31
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * CNS3xxx common devices
+ *
+ * Copyright 2008 Cavium Networks
+ *               Scott Shu
+ * Copyright 2010 MontaVista Software, LLC.
+ *               Anton Vorontsov <avorontsov@mvista.com>
+ *
+ * This file 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/io.h>
+#include <linux/init.h>
+#include <linux/compiler.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <mach/cns3xxx.h>
+#include <mach/irqs.h>
+#include "core.h"
+#include "devices.h"
+
+/*
+ * AHCI
+ */
+static struct resource cns3xxx_ahci_resource[] = {
+       [0] = {
+               .start  = CNS3XXX_SATA2_BASE,
+               .end    = CNS3XXX_SATA2_BASE + CNS3XXX_SATA2_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_CNS3XXX_SATA,
+               .end    = IRQ_CNS3XXX_SATA,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 cns3xxx_ahci_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device cns3xxx_ahci_pdev = {
+       .name           = "ahci",
+       .id             = 0,
+       .resource       = cns3xxx_ahci_resource,
+       .num_resources  = ARRAY_SIZE(cns3xxx_ahci_resource),
+       .dev            = {
+               .dma_mask               = &cns3xxx_ahci_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+void __init cns3xxx_ahci_init(void)
+{
+       u32 tmp;
+
+       tmp = __raw_readl(MISC_SATA_POWER_MODE);
+       tmp |= 0x1 << 16; /* Disable SATA PHY 0 from SLUMBER Mode */
+       tmp |= 0x1 << 17; /* Disable SATA PHY 1 from SLUMBER Mode */
+       __raw_writel(tmp, MISC_SATA_POWER_MODE);
+
+       /* Enable SATA PHY */
+       cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY0);
+       cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY1);
+
+       /* Enable SATA Clock */
+       cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_SATA);
+
+       /* De-Asscer SATA Reset */
+       cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SATA));
+
+       platform_device_register(&cns3xxx_ahci_pdev);
+}
+
+/*
+ * SDHCI
+ */
+static struct resource cns3xxx_sdhci_resources[] = {
+       [0] = {
+               .start = CNS3XXX_SDIO_BASE,
+               .end   = CNS3XXX_SDIO_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_CNS3XXX_SDIO,
+               .end   = IRQ_CNS3XXX_SDIO,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cns3xxx_sdhci_pdev = {
+       .name           = "sdhci-cns3xxx",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(cns3xxx_sdhci_resources),
+       .resource       = cns3xxx_sdhci_resources,
+};
+
+void __init cns3xxx_sdhci_init(void)
+{
+       u32 __iomem *gpioa = __io(CNS3XXX_MISC_BASE_VIRT + 0x0014);
+       u32 gpioa_pins = __raw_readl(gpioa);
+
+       /* MMC/SD pins share with GPIOA */
+       gpioa_pins |= 0x1fff0004;
+       __raw_writel(gpioa_pins, gpioa);
+
+       cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO));
+       cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO));
+
+       platform_device_register(&cns3xxx_sdhci_pdev);
+}
diff --git a/arch/arm/mach-cns3xxx/devices.h b/arch/arm/mach-cns3xxx/devices.h
new file mode 100644 (file)
index 0000000..27e15a1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * CNS3xxx common devices
+ *
+ * Copyright 2008 Cavium Networks
+ *               Scott Shu
+ * Copyright 2010 MontaVista Software, LLC.
+ *               Anton Vorontsov <avorontsov@mvista.com>
+ *
+ * This file 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 __CNS3XXX_DEVICES_H_
+#define __CNS3XXX_DEVICES_H_
+
+void __init cns3xxx_ahci_init(void);
+void __init cns3xxx_sdhci_init(void);
+
+#endif /* __CNS3XXX_DEVICES_H_ */
index 8a2f5a21d4ee3ab63843b6311606d55aaa298352..6dbce13771ca49c83c89dde5b4f0b6f734e20c1f 100644 (file)
  * Misc block
  */
 #define MISC_MEM_MAP(offs) (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + (offs))
-#define MISC_MEM_MAP_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_MISC_BASE_VIRT + (offset))))
-
-#define MISC_MEMORY_REMAP_REG                  MISC_MEM_MAP_VALUE(0x00)
-#define MISC_CHIP_CONFIG_REG                   MISC_MEM_MAP_VALUE(0x04)
-#define MISC_DEBUG_PROBE_DATA_REG              MISC_MEM_MAP_VALUE(0x08)
-#define MISC_DEBUG_PROBE_SELECTION_REG         MISC_MEM_MAP_VALUE(0x0C)
-#define MISC_IO_PIN_FUNC_SELECTION_REG         MISC_MEM_MAP_VALUE(0x10)
-#define MISC_GPIOA_PIN_ENABLE_REG              MISC_MEM_MAP_VALUE(0x14)
-#define MISC_GPIOB_PIN_ENABLE_REG              MISC_MEM_MAP_VALUE(0x18)
-#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_A      MISC_MEM_MAP_VALUE(0x1C)
-#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_B      MISC_MEM_MAP_VALUE(0x20)
-#define MISC_GPIOA_15_0_PULL_CTRL_REG          MISC_MEM_MAP_VALUE(0x24)
-#define MISC_GPIOA_16_31_PULL_CTRL_REG         MISC_MEM_MAP_VALUE(0x28)
-#define MISC_GPIOB_15_0_PULL_CTRL_REG          MISC_MEM_MAP_VALUE(0x2C)
-#define MISC_GPIOB_16_31_PULL_CTRL_REG         MISC_MEM_MAP_VALUE(0x30)
-#define MISC_IO_PULL_CTRL_REG                  MISC_MEM_MAP_VALUE(0x34)
-#define MISC_E_FUSE_31_0_REG                   MISC_MEM_MAP_VALUE(0x40)
-#define MISC_E_FUSE_63_32_REG                  MISC_MEM_MAP_VALUE(0x44)
-#define MISC_E_FUSE_95_64_REG                  MISC_MEM_MAP_VALUE(0x48)
-#define MISC_E_FUSE_127_96_REG                 MISC_MEM_MAP_VALUE(0x4C)
-#define MISC_SOFTWARE_TEST_1_REG               MISC_MEM_MAP_VALUE(0x50)
-#define MISC_SOFTWARE_TEST_2_REG               MISC_MEM_MAP_VALUE(0x54)
-
-#define MISC_SATA_POWER_MODE                   MISC_MEM_MAP_VALUE(0x310)
-
-#define MISC_USB_CFG_REG                       MISC_MEM_MAP_VALUE(0x800)
-#define MISC_USB_STS_REG                       MISC_MEM_MAP_VALUE(0x804)
-#define MISC_USBPHY00_CFG_REG                  MISC_MEM_MAP_VALUE(0x808)
-#define MISC_USBPHY01_CFG_REG                  MISC_MEM_MAP_VALUE(0x80c)
-#define MISC_USBPHY10_CFG_REG                  MISC_MEM_MAP_VALUE(0x810)
-#define MISC_USBPHY11_CFG_REG                  MISC_MEM_MAP_VALUE(0x814)
+
+#define MISC_MEMORY_REMAP_REG                  MISC_MEM_MAP(0x00)
+#define MISC_CHIP_CONFIG_REG                   MISC_MEM_MAP(0x04)
+#define MISC_DEBUG_PROBE_DATA_REG              MISC_MEM_MAP(0x08)
+#define MISC_DEBUG_PROBE_SELECTION_REG         MISC_MEM_MAP(0x0C)
+#define MISC_IO_PIN_FUNC_SELECTION_REG         MISC_MEM_MAP(0x10)
+#define MISC_GPIOA_PIN_ENABLE_REG              MISC_MEM_MAP(0x14)
+#define MISC_GPIOB_PIN_ENABLE_REG              MISC_MEM_MAP(0x18)
+#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_A      MISC_MEM_MAP(0x1C)
+#define MISC_IO_PAD_DRIVE_STRENGTH_CTRL_B      MISC_MEM_MAP(0x20)
+#define MISC_GPIOA_15_0_PULL_CTRL_REG          MISC_MEM_MAP(0x24)
+#define MISC_GPIOA_16_31_PULL_CTRL_REG         MISC_MEM_MAP(0x28)
+#define MISC_GPIOB_15_0_PULL_CTRL_REG          MISC_MEM_MAP(0x2C)
+#define MISC_GPIOB_16_31_PULL_CTRL_REG         MISC_MEM_MAP(0x30)
+#define MISC_IO_PULL_CTRL_REG                  MISC_MEM_MAP(0x34)
+#define MISC_E_FUSE_31_0_REG                   MISC_MEM_MAP(0x40)
+#define MISC_E_FUSE_63_32_REG                  MISC_MEM_MAP(0x44)
+#define MISC_E_FUSE_95_64_REG                  MISC_MEM_MAP(0x48)
+#define MISC_E_FUSE_127_96_REG                 MISC_MEM_MAP(0x4C)
+#define MISC_SOFTWARE_TEST_1_REG               MISC_MEM_MAP(0x50)
+#define MISC_SOFTWARE_TEST_2_REG               MISC_MEM_MAP(0x54)
+
+#define MISC_SATA_POWER_MODE                   MISC_MEM_MAP(0x310)
+
+#define MISC_USB_CFG_REG                       MISC_MEM_MAP(0x800)
+#define MISC_USB_STS_REG                       MISC_MEM_MAP(0x804)
+#define MISC_USBPHY00_CFG_REG                  MISC_MEM_MAP(0x808)
+#define MISC_USBPHY01_CFG_REG                  MISC_MEM_MAP(0x80c)
+#define MISC_USBPHY10_CFG_REG                  MISC_MEM_MAP(0x810)
+#define MISC_USBPHY11_CFG_REG                  MISC_MEM_MAP(0x814)
 
 #define MISC_PCIEPHY_CMCTL(x)                  MISC_MEM_MAP(0x900 + (x) * 0x004)
 #define MISC_PCIEPHY_CTL(x)                    MISC_MEM_MAP(0x940 + (x) * 0x100)
 /*
  * Power management and clock control
  */
-#define PMU_REG_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_PM_BASE_VIRT + (offset))))
-
-#define PM_CLK_GATE_REG                                        PMU_REG_VALUE(0x000)
-#define PM_SOFT_RST_REG                                        PMU_REG_VALUE(0x004)
-#define PM_HS_CFG_REG                                  PMU_REG_VALUE(0x008)
-#define PM_CACTIVE_STA_REG                             PMU_REG_VALUE(0x00C)
-#define PM_PWR_STA_REG                                 PMU_REG_VALUE(0x010)
-#define PM_CLK_CTRL_REG                                        PMU_REG_VALUE(0x014)
-#define PM_PLL_LCD_I2S_CTRL_REG                                PMU_REG_VALUE(0x018)
-#define PM_PLL_HM_PD_CTRL_REG                          PMU_REG_VALUE(0x01C)
-#define PM_REGULAT_CTRL_REG                            PMU_REG_VALUE(0x020)
-#define PM_WDT_CTRL_REG                                        PMU_REG_VALUE(0x024)
-#define PM_WU_CTRL0_REG                                        PMU_REG_VALUE(0x028)
-#define PM_WU_CTRL1_REG                                        PMU_REG_VALUE(0x02C)
-#define PM_CSR_REG                                     PMU_REG_VALUE(0x030)
+#define PMU_MEM_MAP(offs) (void __iomem *)(CNS3XXX_PM_BASE_VIRT + (offs))
+
+#define PM_CLK_GATE_REG                                        PMU_MEM_MAP(0x000)
+#define PM_SOFT_RST_REG                                        PMU_MEM_MAP(0x004)
+#define PM_HS_CFG_REG                                  PMU_MEM_MAP(0x008)
+#define PM_CACTIVE_STA_REG                             PMU_MEM_MAP(0x00C)
+#define PM_PWR_STA_REG                                 PMU_MEM_MAP(0x010)
+#define PM_CLK_CTRL_REG                                        PMU_MEM_MAP(0x014)
+#define PM_PLL_LCD_I2S_CTRL_REG                                PMU_MEM_MAP(0x018)
+#define PM_PLL_HM_PD_CTRL_REG                          PMU_MEM_MAP(0x01C)
+#define PM_REGULAT_CTRL_REG                            PMU_MEM_MAP(0x020)
+#define PM_WDT_CTRL_REG                                        PMU_MEM_MAP(0x024)
+#define PM_WU_CTRL0_REG                                        PMU_MEM_MAP(0x028)
+#define PM_WU_CTRL1_REG                                        PMU_MEM_MAP(0x02C)
+#define PM_CSR_REG                                     PMU_MEM_MAP(0x030)
 
 /* PM_CLK_GATE_REG */
 #define PM_CLK_GATE_REG_OFFSET_SDIO                    (25)
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
new file mode 100644 (file)
index 0000000..38088c3
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * PCI-E support for CNS3xxx
+ *
+ * Copyright 2008 Cavium Networks
+ *               Richard Liu <richard.liu@caviumnetworks.com>
+ * Copyright 2010 MontaVista Software, LLC.
+ *               Anton Vorontsov <avorontsov@mvista.com>
+ *
+ * This file 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/kernel.h>
+#include <linux/bug.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <asm/mach/map.h>
+#include <mach/cns3xxx.h>
+#include "core.h"
+
+enum cns3xxx_access_type {
+       CNS3XXX_HOST_TYPE = 0,
+       CNS3XXX_CFG0_TYPE,
+       CNS3XXX_CFG1_TYPE,
+       CNS3XXX_NUM_ACCESS_TYPES,
+};
+
+struct cns3xxx_pcie {
+       struct map_desc cfg_bases[CNS3XXX_NUM_ACCESS_TYPES];
+       unsigned int irqs[2];
+       struct resource res_io;
+       struct resource res_mem;
+       struct hw_pci hw_pci;
+
+       bool linked;
+};
+
+static struct cns3xxx_pcie cns3xxx_pcie[]; /* forward decl. */
+
+static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata)
+{
+       struct pci_sys_data *root = sysdata;
+
+       return &cns3xxx_pcie[root->domain];
+}
+
+static struct cns3xxx_pcie *pdev_to_cnspci(struct pci_dev *dev)
+{
+       return sysdata_to_cnspci(dev->sysdata);
+}
+
+static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus)
+{
+       return sysdata_to_cnspci(bus->sysdata);
+}
+
+static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
+                                 unsigned int devfn, int where)
+{
+       struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
+       int busno = bus->number;
+       int slot = PCI_SLOT(devfn);
+       int offset;
+       enum cns3xxx_access_type type;
+       void __iomem *base;
+
+       /* If there is no link, just show the CNS PCI bridge. */
+       if (!cnspci->linked && (busno > 0 || slot > 0))
+               return NULL;
+
+       /*
+        * The CNS PCI bridge doesn't fit into the PCI hierarchy, though
+        * we still want to access it. For this to work, we must place
+        * the first device on the same bus as the CNS PCI bridge.
+        */
+       if (busno == 0) {
+               if (slot > 1)
+                       return NULL;
+               type = slot;
+       } else {
+               type = CNS3XXX_CFG1_TYPE;
+       }
+
+       base = (void __iomem *)cnspci->cfg_bases[type].virtual;
+       offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
+
+       return base + offset;
+}
+
+static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                                  int where, int size, u32 *val)
+{
+       u32 v;
+       void __iomem *base;
+       u32 mask = (0x1ull << (size * 8)) - 1;
+       int shift = (where % 4) * 8;
+
+       base = cns3xxx_pci_cfg_base(bus, devfn, where);
+       if (!base) {
+               *val = 0xffffffff;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       v = __raw_readl(base);
+
+       if (bus->number == 0 && devfn == 0 &&
+                       (where & 0xffc) == PCI_CLASS_REVISION) {
+               /*
+                * RC's class is 0xb, but Linux PCI driver needs 0x604
+                * for a PCIe bridge. So we must fixup the class code
+                * to 0x604 here.
+                */
+               v &= 0xff;
+               v |= 0x604 << 16;
+       }
+
+       *val = (v >> shift) & mask;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int cns3xxx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+                                   int where, int size, u32 val)
+{
+       u32 v;
+       void __iomem *base;
+       u32 mask = (0x1ull << (size * 8)) - 1;
+       int shift = (where % 4) * 8;
+
+       base = cns3xxx_pci_cfg_base(bus, devfn, where);
+       if (!base)
+               return PCIBIOS_SUCCESSFUL;
+
+       v = __raw_readl(base);
+
+       v &= ~(mask << shift);
+       v |= (val & mask) << shift;
+
+       __raw_writel(v, base);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
+       struct resource *res_io = &cnspci->res_io;
+       struct resource *res_mem = &cnspci->res_mem;
+       struct resource **sysres = sys->resource;
+
+       BUG_ON(request_resource(&iomem_resource, res_io) ||
+              request_resource(&iomem_resource, res_mem));
+
+       sysres[0] = res_io;
+       sysres[1] = res_mem;
+
+       return 1;
+}
+
+static struct pci_ops cns3xxx_pcie_ops = {
+       .read = cns3xxx_pci_read_config,
+       .write = cns3xxx_pci_write_config,
+};
+
+static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
+{
+       return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
+}
+
+static int cns3xxx_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
+       int irq = cnspci->irqs[slot];
+
+       pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n",
+               pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn),
+               PCI_FUNC(dev->devfn), slot, pin, irq);
+
+       return irq;
+}
+
+static struct cns3xxx_pcie cns3xxx_pcie[] = {
+       [0] = {
+               .cfg_bases = {
+                       [CNS3XXX_HOST_TYPE] = {
+                               .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT,
+                               .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE),
+                               .length = SZ_16M,
+                               .type = MT_DEVICE,
+                       },
+                       [CNS3XXX_CFG0_TYPE] = {
+                               .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT,
+                               .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE),
+                               .length = SZ_16M,
+                               .type = MT_DEVICE,
+                       },
+                       [CNS3XXX_CFG1_TYPE] = {
+                               .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT,
+                               .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE),
+                               .length = SZ_16M,
+                               .type = MT_DEVICE,
+                       },
+               },
+               .res_io = {
+                       .name = "PCIe0 I/O space",
+                       .start = CNS3XXX_PCIE0_IO_BASE,
+                       .end = CNS3XXX_PCIE0_IO_BASE + SZ_16M - 1,
+                       .flags = IORESOURCE_IO,
+               },
+               .res_mem = {
+                       .name = "PCIe0 non-prefetchable",
+                       .start = CNS3XXX_PCIE0_MEM_BASE,
+                       .end = CNS3XXX_PCIE0_MEM_BASE + SZ_16M - 1,
+                       .flags = IORESOURCE_MEM,
+               },
+               .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, },
+               .hw_pci = {
+                       .domain = 0,
+                       .swizzle = pci_std_swizzle,
+                       .nr_controllers = 1,
+                       .setup = cns3xxx_pci_setup,
+                       .scan = cns3xxx_pci_scan_bus,
+                       .map_irq = cns3xxx_pcie_map_irq,
+               },
+       },
+       [1] = {
+               .cfg_bases = {
+                       [CNS3XXX_HOST_TYPE] = {
+                               .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT,
+                               .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE),
+                               .length = SZ_16M,
+                               .type = MT_DEVICE,
+                       },
+                       [CNS3XXX_CFG0_TYPE] = {
+                               .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT,
+                               .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE),
+                               .length = SZ_16M,
+                               .type = MT_DEVICE,
+                       },
+                       [CNS3XXX_CFG1_TYPE] = {
+                               .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT,
+                               .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE),
+                               .length = SZ_16M,
+                               .type = MT_DEVICE,
+                       },
+               },
+               .res_io = {
+                       .name = "PCIe1 I/O space",
+                       .start = CNS3XXX_PCIE1_IO_BASE,
+                       .end = CNS3XXX_PCIE1_IO_BASE + SZ_16M - 1,
+                       .flags = IORESOURCE_IO,
+               },
+               .res_mem = {
+                       .name = "PCIe1 non-prefetchable",
+                       .start = CNS3XXX_PCIE1_MEM_BASE,
+                       .end = CNS3XXX_PCIE1_MEM_BASE + SZ_16M - 1,
+                       .flags = IORESOURCE_MEM,
+               },
+               .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, },
+               .hw_pci = {
+                       .domain = 1,
+                       .swizzle = pci_std_swizzle,
+                       .nr_controllers = 1,
+                       .setup = cns3xxx_pci_setup,
+                       .scan = cns3xxx_pci_scan_bus,
+                       .map_irq = cns3xxx_pcie_map_irq,
+               },
+       },
+};
+
+static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci)
+{
+       int port = cnspci->hw_pci.domain;
+       u32 reg;
+       unsigned long time;
+
+       reg = __raw_readl(MISC_PCIE_CTRL(port));
+       /*
+        * Enable Application Request to 1, it will exit L1 automatically,
+        * but when chip back, it will use another clock, still can use 0x1.
+        */
+       reg |= 0x3;
+       __raw_writel(reg, MISC_PCIE_CTRL(port));
+
+       pr_info("PCIe: Port[%d] Enable PCIe LTSSM\n", port);
+       pr_info("PCIe: Port[%d] Check data link layer...", port);
+
+       time = jiffies;
+       while (1) {
+               reg = __raw_readl(MISC_PCIE_PM_DEBUG(port));
+               if (reg & 0x1) {
+                       pr_info("Link up.\n");
+                       cnspci->linked = 1;
+                       break;
+               } else if (time_after(jiffies, time + 50)) {
+                       pr_info("Device not found.\n");
+                       break;
+               }
+       }
+}
+
+static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
+{
+       int port = cnspci->hw_pci.domain;
+       struct pci_sys_data sd = {
+               .domain = port,
+       };
+       struct pci_bus bus = {
+               .number = 0,
+               .ops = &cns3xxx_pcie_ops,
+               .sysdata = &sd,
+       };
+       u32 io_base = cnspci->res_io.start >> 16;
+       u32 mem_base = cnspci->res_mem.start >> 16;
+       u32 host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].pfn;
+       u32 cfg0_base = cnspci->cfg_bases[CNS3XXX_CFG0_TYPE].pfn;
+       u32 devfn = 0;
+       u8 tmp8;
+       u16 pos;
+       u16 dc;
+
+       host_base = (__pfn_to_phys(host_base) - 1) >> 16;
+       cfg0_base = (__pfn_to_phys(cfg0_base) - 1) >> 16;
+
+       pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
+       pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
+       pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);
+
+       pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8);
+       pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8);
+       pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);
+
+       pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base);
+       pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, host_base);
+       pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base);
+       pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, cfg0_base);
+
+       if (!cnspci->linked)
+               return;
+
+       /* Set Device Max_Read_Request_Size to 128 byte */
+       devfn = PCI_DEVFN(1, 0);
+       pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
+       pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
+       dc &= ~(0x3 << 12);     /* Clear Device Control Register [14:12] */
+       pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc);
+       pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
+       if (!(dc & (0x3 << 12)))
+               pr_info("PCIe: Set Device Max_Read_Request_Size to 128 byte\n");
+
+       /* Disable PCIe0 Interrupt Mask INTA to INTD */
+       __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port));
+}
+
+static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
+                                     struct pt_regs *regs)
+{
+       if (fsr & (1 << 10))
+               regs->ARM_pc += 4;
+       return 0;
+}
+
+static int __init cns3xxx_pcie_init(void)
+{
+       int i;
+
+       hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS,
+                       "imprecise external abort");
+
+       for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
+               iotable_init(cns3xxx_pcie[i].cfg_bases,
+                            ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases));
+               cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
+               cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
+               cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
+               cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]);
+               pci_common_init(&cns3xxx_pcie[i].hw_pci);
+       }
+
+       pci_assign_unassigned_resources();
+
+       return 0;
+}
+device_initcall(cns3xxx_pcie_init);
index 725e1a4fc23103ecd01df12eea9483d3f81a42f3..38e44706feabf43a69a9a3429f3a6753b51d34a0 100644 (file)
@@ -6,18 +6,25 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <mach/system.h>
 #include <mach/cns3xxx.h>
 
 void cns3xxx_pwr_clk_en(unsigned int block)
 {
-       PM_CLK_GATE_REG |= (block & PM_CLK_GATE_REG_MASK);
+       u32 reg = __raw_readl(PM_CLK_GATE_REG);
+
+       reg |= (block & PM_CLK_GATE_REG_MASK);
+       __raw_writel(reg, PM_CLK_GATE_REG);
 }
 
 void cns3xxx_pwr_power_up(unsigned int block)
 {
-       PM_PLL_HM_PD_CTRL_REG &= ~(block & CNS3XXX_PWR_PLL_ALL);
+       u32 reg = __raw_readl(PM_PLL_HM_PD_CTRL_REG);
+
+       reg &= ~(block & CNS3XXX_PWR_PLL_ALL);
+       __raw_writel(reg, PM_PLL_HM_PD_CTRL_REG);
 
        /* Wait for 300us for the PLL output clock locked. */
        udelay(300);
@@ -25,22 +32,29 @@ void cns3xxx_pwr_power_up(unsigned int block)
 
 void cns3xxx_pwr_power_down(unsigned int block)
 {
+       u32 reg = __raw_readl(PM_PLL_HM_PD_CTRL_REG);
+
        /* write '1' to power down */
-       PM_PLL_HM_PD_CTRL_REG |= (block & CNS3XXX_PWR_PLL_ALL);
+       reg |= (block & CNS3XXX_PWR_PLL_ALL);
+       __raw_writel(reg, PM_PLL_HM_PD_CTRL_REG);
 };
 
 static void cns3xxx_pwr_soft_rst_force(unsigned int block)
 {
+       u32 reg = __raw_readl(PM_SOFT_RST_REG);
+
        /*
         * bit 0, 28, 29 => program low to reset,
         * the other else program low and then high
         */
        if (block & 0x30000001) {
-               PM_SOFT_RST_REG &= ~(block & PM_SOFT_RST_REG_MASK);
+               reg &= ~(block & PM_SOFT_RST_REG_MASK);
        } else {
-               PM_SOFT_RST_REG &= ~(block & PM_SOFT_RST_REG_MASK);
-               PM_SOFT_RST_REG |= (block & PM_SOFT_RST_REG_MASK);
+               reg &= ~(block & PM_SOFT_RST_REG_MASK);
+               reg |= (block & PM_SOFT_RST_REG_MASK);
        }
+
+       __raw_writel(reg, PM_SOFT_RST_REG);
 }
 
 void cns3xxx_pwr_soft_rst(unsigned int block)
@@ -73,12 +87,13 @@ void arch_reset(char mode, const char *cmd)
  */
 int cns3xxx_cpu_clock(void)
 {
+       u32 reg = __raw_readl(PM_CLK_CTRL_REG);
        int cpu;
        int cpu_sel;
        int div_sel;
 
-       cpu_sel = (PM_CLK_CTRL_REG >> PM_CLK_CTRL_REG_OFFSET_PLL_CPU_SEL) & 0xf;
-       div_sel = (PM_CLK_CTRL_REG >> PM_CLK_CTRL_REG_OFFSET_CPU_CLK_DIV) & 0x3;
+       cpu_sel = (reg >> PM_CLK_CTRL_REG_OFFSET_PLL_CPU_SEL) & 0xf;
+       div_sel = (reg >> PM_CLK_CTRL_REG_OFFSET_CPU_CLK_DIV) & 0x3;
 
        cpu = (300 + ((cpu_sel / 3) * 100) + ((cpu_sel % 3) * 33)) >> div_sel;
 
index a91edfb8beeac3109542989c957256436fd5a5c8..22eb97c1c30b48c89e6e2f397f73ee5727f5240a 100644 (file)
  * below 128M
  */
 static inline void
-__arch_adjust_zones(int node, unsigned long *size, unsigned long *holes)
+__arch_adjust_zones(unsigned long *size, unsigned long *holes)
 {
        unsigned int sz = (128<<20) >> PAGE_SHIFT;
 
-       if (node != 0)
-               sz = 0;
-
        size[1] = size[0] - sz;
        size[0] = sz;
 }
 
-#define arch_adjust_zones(node, zone_size, holes) \
-        if ((meminfo.bank[0].size >> 20) > 128) __arch_adjust_zones(node, zone_size, holes)
+#define arch_adjust_zones(zone_size, holes) \
+        if ((meminfo.bank[0].size >> 20) > 128) __arch_adjust_zones(zone_size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + (128<<20) - 1)
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + (128<<20))
index 5da2cf402c81d9773ce979ead618381e0efcd3e2..f7a12586a1f5eaf9c1b0316b6efc2b914a63fa30 100644 (file)
@@ -752,6 +752,67 @@ void __init dove_xor1_init(void)
        platform_device_register(&dove_xor11_channel);
 }
 
+/*****************************************************************************
+ * SDIO
+ ****************************************************************************/
+static u64 sdio_dmamask = DMA_BIT_MASK(32);
+
+static struct resource dove_sdio0_resources[] = {
+       {
+               .start  = DOVE_SDIO0_PHYS_BASE,
+               .end    = DOVE_SDIO0_PHYS_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_SDIO0,
+               .end    = IRQ_DOVE_SDIO0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_sdio0 = {
+       .name           = "sdhci-mv",
+       .id             = 0,
+       .dev            = {
+               .dma_mask               = &sdio_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = dove_sdio0_resources,
+       .num_resources  = ARRAY_SIZE(dove_sdio0_resources),
+};
+
+void __init dove_sdio0_init(void)
+{
+       platform_device_register(&dove_sdio0);
+}
+
+static struct resource dove_sdio1_resources[] = {
+       {
+               .start  = DOVE_SDIO1_PHYS_BASE,
+               .end    = DOVE_SDIO1_PHYS_BASE + 0xff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_DOVE_SDIO1,
+               .end    = IRQ_DOVE_SDIO1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dove_sdio1 = {
+       .name           = "sdhci-mv",
+       .id             = 1,
+       .dev            = {
+               .dma_mask               = &sdio_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = dove_sdio1_resources,
+       .num_resources  = ARRAY_SIZE(dove_sdio1_resources),
+};
+
+void __init dove_sdio1_init(void)
+{
+       platform_device_register(&dove_sdio1);
+}
+
 void __init dove_init(void)
 {
        int tclk;
index b29e8937de4fd0acf9148bb0880dcc1c1ccafc94..a51517c3fe7654b629f4772ae2ef16cc63280f5f 100644 (file)
@@ -36,5 +36,7 @@ void dove_uart3_init(void);
 void dove_spi0_init(void);
 void dove_spi1_init(void);
 void dove_i2c_init(void);
+void dove_sdio0_init(void);
+void dove_sdio1_init(void);
 
 #endif
index f2971b7452242132a7ddc07552af66a5c330c911..bef70460fbc669353907355d3b9ca04f0a8308f3 100644 (file)
@@ -82,6 +82,8 @@ static void __init dove_db_init(void)
        dove_ehci0_init();
        dove_ehci1_init();
        dove_sata_init(&dove_db_sata_data);
+       dove_sdio0_init();
+       dove_sdio1_init();
        dove_spi0_init();
        dove_spi1_init();
        dove_uart0_init();
index 3a1a855bfdcace3e35591a50ede18edb6f2a1ec3..f744f676783f3024c0d18be2bff733432b260d9c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 
 #include <mach/hardware.h>
 
 #include <asm/mach/arch.h>
 
 
-static struct physmap_flash_data adssphere_flash_data = {
-       .width          = 4,
-};
-
-static struct resource adssphere_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device adssphere_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &adssphere_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &adssphere_flash_resource,
-};
-
 static struct ep93xx_eth_data __initdata adssphere_eth_data = {
        .phy_id         = 1,
 };
@@ -48,8 +27,7 @@ static struct ep93xx_eth_data __initdata adssphere_eth_data = {
 static void __init adssphere_init_machine(void)
 {
        ep93xx_init_devices();
-       platform_device_register(&adssphere_flash);
-
+       ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M);
        ep93xx_register_eth(&adssphere_eth_data, 1);
 }
 
index e29bdef9b2e201ea345c4139487e4895dffad94d..7f3039761d91aecf0c0c46c84424f5ad4c1bf743 100644 (file)
@@ -185,7 +185,7 @@ static struct clk_lookup clocks[] = {
        INIT_CK(NULL,                   "pll1",         &clk_pll1),
        INIT_CK(NULL,                   "fclk",         &clk_f),
        INIT_CK(NULL,                   "hclk",         &clk_h),
-       INIT_CK(NULL,                   "pclk",         &clk_p),
+       INIT_CK(NULL,                   "apb_pclk",     &clk_p),
        INIT_CK(NULL,                   "pll2",         &clk_pll2),
        INIT_CK("ep93xx-ohci",          NULL,           &clk_usb_host),
        INIT_CK("ep93xx-keypad",        NULL,           &clk_keypad),
index 9092677f63eb739a529d137b5b1be891b11f53da..8e37a045188cbcf4bc334d521186b8d4a2871d5d 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/termios.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
+#include <linux/mtd/physmap.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <linux/spi/spi.h>
@@ -215,8 +216,8 @@ void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
        spin_lock_irqsave(&syscon_swlock, flags);
 
        val = __raw_readl(EP93XX_SYSCON_DEVCFG);
-       val |= set_bits;
        val &= ~clear_bits;
+       val |= set_bits;
        __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
        __raw_writel(val, EP93XX_SYSCON_DEVCFG);
 
@@ -347,6 +348,43 @@ static struct platform_device ep93xx_ohci_device = {
 };
 
 
+/*************************************************************************
+ * EP93xx physmap'ed flash
+ *************************************************************************/
+static struct physmap_flash_data ep93xx_flash_data;
+
+static struct resource ep93xx_flash_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device ep93xx_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &ep93xx_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &ep93xx_flash_resource,
+};
+
+/**
+ * ep93xx_register_flash() - Register the external flash device.
+ * @width:     bank width in octets
+ * @start:     resource start address
+ * @size:      resource size
+ */
+void __init ep93xx_register_flash(unsigned int width,
+                                 resource_size_t start, resource_size_t size)
+{
+       ep93xx_flash_data.width         = width;
+
+       ep93xx_flash_resource.start     = start;
+       ep93xx_flash_resource.end       = start + size - 1;
+
+       platform_device_register(&ep93xx_flash);
+}
+
+
 /*************************************************************************
  * EP93xx ethernet peripheral handling
  *************************************************************************/
@@ -620,6 +658,11 @@ static struct platform_device ep93xx_fb_device = {
        .resource               = ep93xx_fb_resource,
 };
 
+static struct platform_device ep93xx_bl_device = {
+       .name           = "ep93xx-bl",
+       .id             = -1,
+};
+
 /**
  * ep93xx_register_fb - Register the framebuffer platform device.
  * @data:      platform specific framebuffer configuration (__initdata)
@@ -628,6 +671,7 @@ void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data)
 {
        ep93xxfb_data = *data;
        platform_device_register(&ep93xx_fb_device);
+       platform_device_register(&ep93xx_bl_device);
 }
 
 
index 3884182cd3623e8799b00323115d097f1894e4e9..c2ce9034ba87f5b856cb6e1cae89fb69060b8ffe 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <asm/mach/arch.h>
 
 
-static struct physmap_flash_data edb93xx_flash_data;
-
-static struct resource edb93xx_flash_resource = {
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb93xx_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb93xx_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb93xx_flash_resource,
-};
-
-static void __init __edb93xx_register_flash(unsigned int width,
-                       resource_size_t start, resource_size_t size)
-{
-       edb93xx_flash_data.width        = width;
-       edb93xx_flash_resource.start    = start;
-       edb93xx_flash_resource.end      = start + size - 1;
-
-       platform_device_register(&edb93xx_flash);
-}
-
 static void __init edb93xx_register_flash(void)
 {
        if (machine_is_edb9307() || machine_is_edb9312() ||
            machine_is_edb9315()) {
-               __edb93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M);
+               ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M);
        } else {
-               __edb93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
+               ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
        }
 }
 
index a809618e9f059043b706bf25e57ffcf070dd3ff4..d97168c0ba336fa22179328b9dc72316807c13bb 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 
 #include <mach/hardware.h>
 
 #include <asm/mach/arch.h>
 
 
-static struct physmap_flash_data gesbc9312_flash_data = {
-       .width          = 4,
-};
-
-static struct resource gesbc9312_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_8M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device gesbc9312_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &gesbc9312_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &gesbc9312_flash_resource,
-};
-
 static struct ep93xx_eth_data __initdata gesbc9312_eth_data = {
        .phy_id         = 1,
 };
@@ -48,8 +27,7 @@ static struct ep93xx_eth_data __initdata gesbc9312_eth_data = {
 static void __init gesbc9312_init_machine(void)
 {
        ep93xx_init_devices();
-       platform_device_register(&gesbc9312_flash);
-
+       ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_8M);
        ep93xx_register_eth(&gesbc9312_eth_data, 0);
 }
 
index 9a4413dd44bb6e1cd2ac6cbc291cfd87b7220d6f..a6c09176334ce1a7028705feeddfc38ddadf235e 100644 (file)
@@ -43,6 +43,9 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
 
 unsigned int ep93xx_chip_revision(void);
 
+void ep93xx_register_flash(unsigned int width,
+                          resource_size_t start, resource_size_t size);
+
 void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
 void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
                         struct i2c_board_info *devices, int num);
index 1cc911b4efa659dbfbc7e35aee6f80236e81e800..2ba776320a8282e978d989eea0377d6511dc3ab7 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
  * Micro9-Lite uses a separate MTD map driver for flash support
  * Micro9-Slim has up to 64MB of either 32-bit or 16-bit flash on CS1
  *************************************************************************/
-static struct physmap_flash_data micro9_flash_data;
-
-static struct resource micro9_flash_resource = {
-       .start          = EP93XX_CS1_PHYS_BASE,
-       .end            = EP93XX_CS1_PHYS_BASE + SZ_64M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device micro9_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &micro9_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &micro9_flash_resource,
-};
-
-static void __init __micro9_register_flash(unsigned int width)
-{
-       micro9_flash_data.width = width;
-
-       platform_device_register(&micro9_flash);
-}
-
 static unsigned int __init micro9_detect_bootwidth(void)
 {
        u32 v;
@@ -70,10 +44,17 @@ static unsigned int __init micro9_detect_bootwidth(void)
 
 static void __init micro9_register_flash(void)
 {
+       unsigned int width;
+
        if (machine_is_micro9())
-               __micro9_register_flash(4);
+               width = 4;
        else if (machine_is_micro9m() || machine_is_micro9s())
-               __micro9_register_flash(micro9_detect_bootwidth());
+               width = micro9_detect_bootwidth();
+       else
+               width = 0;
+
+       if (width)
+               ep93xx_register_flash(width, EP93XX_CS1_PHYS_BASE, SZ_64M);
 }
 
 
index 388aec95f60e39fb304ac48c655c413f33129c45..5dded5884133f89e27898567a61163c583fa8f3d 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-static struct physmap_flash_data simone_flash_data = {
-       .width          = 2,
-};
-
-static struct resource simone_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_8M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device simone_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .num_resources  = 1,
-       .resource       = &simone_flash_resource,
-       .dev = {
-               .platform_data  = &simone_flash_data,
-       },
-};
-
 static struct ep93xx_eth_data __initdata simone_eth_data = {
        .phy_id         = 1,
 };
@@ -77,8 +56,7 @@ static struct i2c_board_info __initdata simone_i2c_board_info[] = {
 static void __init simone_init_machine(void)
 {
        ep93xx_init_devices();
-
-       platform_device_register(&simone_flash);
+       ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_8M);
        ep93xx_register_eth(&simone_eth_data, 1);
        ep93xx_register_fb(&simone_fb_info);
        ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
index ae7319e588c7e59ca570173d47d1e95a0fe06d0f..93aeab8af705e8dd3dde989b1658e81e6ed60062 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/m48t86.h>
-#include <linux/mtd/physmap.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
@@ -173,31 +172,13 @@ static struct platform_device ts72xx_nand_flash = {
 };
 
 
-/*************************************************************************
- * NOR flash (TS-7200 only)
- *************************************************************************/
-static struct physmap_flash_data ts72xx_nor_data = {
-       .width          = 2,
-};
-
-static struct resource ts72xx_nor_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device ts72xx_nor_flash = {
-       .name                   = "physmap-flash",
-       .id                     = 0,
-       .dev.platform_data      = &ts72xx_nor_data,
-       .resource               = &ts72xx_nor_resource,
-       .num_resources          = 1,
-};
-
 static void __init ts72xx_register_flash(void)
 {
+       /*
+        * TS7200 has NOR flash all other TS72xx board have NAND flash.
+        */
        if (board_is_ts7200()) {
-               platform_device_register(&ts72xx_nor_flash);
+               ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
        } else {
                resource_size_t start;
 
similarity index 57%
rename from arch/arm/mach-mx2/Kconfig
rename to arch/arm/mach-imx/Kconfig
index 742fd4e6dcb928486d299eec335f95b7cba6a431..c5c0369bb481dff32f4bbb8c214f4859a16787ac 100644 (file)
+config IMX_HAVE_DMA_V1
+       bool
+
+if ARCH_MX1
+
+config SOC_IMX1
+       select CPU_ARM920T
+       select IMX_HAVE_DMA_V1
+       select IMX_HAVE_IOMUX_V1
+       bool
+
+comment "MX1 platforms:"
+config MACH_MXLADS
+       bool
+
+config ARCH_MX1ADS
+       bool "MX1ADS platform"
+       select MACH_MXLADS
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       help
+         Say Y here if you are using Motorola MX1ADS/MXLADS boards
+
+config MACH_SCB9328
+       bool "Synertronixx scb9328"
+       select IMX_HAVE_PLATFORM_IMX_UART
+       help
+         Say Y here if you are using a Synertronixx scb9328 board
+
+endif
+
 if ARCH_MX2
 
+config SOC_IMX21
+       select CPU_ARM926T
+       select ARCH_MXC_AUDMUX_V1
+       select IMX_HAVE_DMA_V1
+       select IMX_HAVE_IOMUX_V1
+       bool
+
+config SOC_IMX27
+       select CPU_ARM926T
+       select ARCH_MXC_AUDMUX_V1
+       select IMX_HAVE_DMA_V1
+       select IMX_HAVE_IOMUX_V1
+       bool
+
 choice
        prompt "CPUs:"
        default MACH_MX21
 
 config MACH_MX21
        bool "i.MX21 support"
-       select ARCH_MXC_AUDMUX_V1
+       select SOC_IMX21
        help
          This enables support for Freescale's MX2 based i.MX21 processor.
 
 config MACH_MX27
        bool "i.MX27 support"
-       select ARCH_MXC_AUDMUX_V1
+       select SOC_IMX27
        help
          This enables support for Freescale's MX2 based i.MX27 processor.
 
 endchoice
 
-comment "MX2 platforms:"
+endif
+
+if MACH_MX21
+
+comment "MX21 platforms:"
 
 config MACH_MX21ADS
        bool "MX21ADS platform"
-       depends on MACH_MX21
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        help
          Include support for MX21ADS platform. This includes specific
          configurations for the board and its peripherals.
 
+endif
+
+if MACH_MX27
+
+comment "MX27 platforms:"
+
 config MACH_MX27ADS
        bool "MX27ADS platform"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        help
          Include support for MX27ADS platform. This includes specific
          configurations for the board and its peripherals.
 
 config MACH_PCM038
        bool "Phytec phyCORE-i.MX27 CPU module (pcm038)"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_SPI_IMX
        select MXC_ULPI if USB_ULPI
        help
          Include support for phyCORE-i.MX27 (aka pcm038) platform. This
@@ -58,7 +119,9 @@ endchoice
 
 config MACH_CPUIMX27
        bool "Eukrea CPUIMX27 module"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        help
          Include support for Eukrea CPUIMX27 platform. This includes
          specific configurations for the module and its peripherals.
@@ -67,9 +130,16 @@ config MACH_EUKREA_CPUIMX27_USESDHC2
        bool "CPUIMX27 integrates SDHC2 module"
        depends on MACH_CPUIMX27
        help
-         This adds support for the internal SDHC2 used on CPUIMX27 used
+         This adds support for the internal SDHC2 used on CPUIMX27
          for wifi or eMMC.
 
+config MACH_EUKREA_CPUIMX27_USEUART4
+       bool "CPUIMX27 integrates UART4 module"
+       depends on MACH_CPUIMX27
+       help
+         This adds support for the internal UART4 used on CPUIMX27
+         for bluetooth.
+
 choice
        prompt "Baseboard"
        depends on MACH_CPUIMX27
@@ -78,6 +148,8 @@ choice
 config MACH_EUKREA_MBIMX27_BASEBOARD
        prompt "Eukrea MBIMX27 development board"
        bool
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_SPI_IMX
        help
          This adds board specific devices that can be found on Eukrea's
          MBIMX27 evaluation board.
@@ -86,21 +158,24 @@ endchoice
 
 config MACH_MX27_3DS
        bool "MX27PDK platform"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_UART
        help
          Include support for MX27PDK platform. This includes specific
          configurations for the board and its peripherals.
 
 config MACH_IMX27LITE
        bool "LogicPD MX27 LITEKIT platform"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_UART
        help
          Include support for MX27 LITEKIT platform. This includes specific
          configurations for the board and its peripherals.
 
 config MACH_PCA100
        bool "Phytec phyCARD-s (pca100)"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_SPI_IMX
        select MXC_ULPI if USB_ULPI
        help
          Include support for phyCARD-s (aka pca100) platform. This
@@ -108,7 +183,9 @@ config MACH_PCA100
 
 config MACH_MXT_TD60
        bool "Maxtrack i-MXT TD60"
-       depends on MACH_MX27
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        help
          Include support for i-MXT (aka td60) platform. This
          includes specific configurations for the module and its peripherals.
similarity index 55%
rename from arch/arm/mach-mx2/Makefile
rename to arch/arm/mach-imx/Makefile
index e3254faac8289655f2997afe2f0d24d1fff8cfbb..46a9fdfbbd157101e22fbd19e1edb6d2c2d893af 100644 (file)
@@ -4,14 +4,24 @@
 
 # Object file lists.
 
-obj-y  :=  devices.o serial.o
+obj-y  :=  devices.o
 
-obj-$(CONFIG_MACH_MX21) += clock_imx21.o mm-imx21.o
+obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o
 
-obj-$(CONFIG_MACH_MX27) += cpu_imx27.o
-obj-$(CONFIG_MACH_MX27) += clock_imx27.o mm-imx27.o
+obj-$(CONFIG_ARCH_MX1) += clock-imx1.o mm-imx1.o
+obj-$(CONFIG_MACH_MX21) += clock-imx21.o mm-imx21.o
+
+obj-$(CONFIG_MACH_MX27) += cpu-imx27.o pm-imx27.o
+obj-$(CONFIG_MACH_MX27) += clock-imx27.o mm-imx27.o
+
+# Support for CMOS sensor interface
+obj-$(CONFIG_MX1_VIDEO)        += mx1-camera-fiq.o mx1-camera-fiq-ksym.o
+
+obj-$(CONFIG_ARCH_MX1ADS) += mach-mx1ads.o
+obj-$(CONFIG_MACH_SCB9328) += mach-scb9328.o
 
 obj-$(CONFIG_MACH_MX21ADS) += mach-mx21ads.o
+
 obj-$(CONFIG_MACH_MX27ADS) += mach-mx27ads.o
 obj-$(CONFIG_MACH_PCM038) += mach-pcm038.o
 obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
similarity index 67%
rename from arch/arm/mach-mx2/Makefile.boot
rename to arch/arm/mach-imx/Makefile.boot
index e867398a8fdbb5304493c40104635e1e40a3f778..7988a85cf07db0453ec39715c38a70067a2ef1d0 100644 (file)
@@ -1,3 +1,7 @@
+zreladdr-$(CONFIG_ARCH_MX1)    := 0x08008000
+params_phys-$(CONFIG_ARCH_MX1) := 0x08000100
+initrd_phys-$(CONFIG_ARCH_MX1) := 0x08800000
+
 zreladdr-$(CONFIG_MACH_MX21)   := 0xC0008000
 params_phys-$(CONFIG_MACH_MX21)        := 0xC0000100
 initrd_phys-$(CONFIG_MACH_MX21)        := 0xC0800000
similarity index 90%
rename from arch/arm/mach-mx1/clock.c
rename to arch/arm/mach-imx/clock-imx1.c
index 6cf2d4a7511dc441561c80fe80ca432cf886d3b5..c05096c38301038292e9b9f6e0bb10990c31433e 100644 (file)
@@ -2,18 +2,17 @@
  *  Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * 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
+ * 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/kernel.h>
 #include <mach/clock.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
-#include "crm_regs.h"
+
+#define IO_ADDR_CCM(off)       (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off)))
+
+/* CCM register addresses */
+#define CCM_CSCR       IO_ADDR_CCM(0x0)
+#define CCM_MPCTL0     IO_ADDR_CCM(0x4)
+#define CCM_SPCTL0     IO_ADDR_CCM(0xc)
+#define CCM_PCDR       IO_ADDR_CCM(0x20)
+
+#define CCM_CSCR_CLKO_OFFSET   29
+#define CCM_CSCR_CLKO_MASK     (0x7 << 29)
+#define CCM_CSCR_USB_OFFSET    26
+#define CCM_CSCR_USB_MASK      (0x7 << 26)
+#define CCM_CSCR_OSC_EN_SHIFT  17
+#define CCM_CSCR_SYSTEM_SEL    (1 << 16)
+#define CCM_CSCR_BCLK_OFFSET   10
+#define CCM_CSCR_BCLK_MASK     (0xf << 10)
+#define CCM_CSCR_PRESC         (1 << 15)
+
+#define CCM_PCDR_PCLK3_OFFSET  16
+#define CCM_PCDR_PCLK3_MASK    (0x7f << 16)
+#define CCM_PCDR_PCLK2_OFFSET  4
+#define CCM_PCDR_PCLK2_MASK    (0xf << 4)
+#define CCM_PCDR_PCLK1_OFFSET  0
+#define CCM_PCDR_PCLK1_MASK    0xf
+
+#define IO_ADDR_SCM(off)       (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off)))
+
+/* SCM register addresses */
+#define SCM_GCCR       IO_ADDR_SCM(0xc)
+
+#define SCM_GCCR_DMA_CLK_EN_OFFSET     3
+#define SCM_GCCR_CSI_CLK_EN_OFFSET     2
+#define SCM_GCCR_MMA_CLK_EN_OFFSET     1
+#define SCM_GCCR_USBD_CLK_EN_OFFSET    0
 
 static int _clk_enable(struct clk *clk)
 {
@@ -596,7 +629,8 @@ int __init mx1_clocks_init(unsigned long fref)
        clk_enable(&hclk);
        clk_enable(&fclk);
 
-       mxc_timer_init(&gpt_clk, IO_ADDRESS(TIM1_BASE_ADDR), TIM1_INT);
+       mxc_timer_init(&gpt_clk, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR),
+                       MX1_TIM1_INT);
 
        return 0;
 }
similarity index 99%
rename from arch/arm/mach-mx2/clock_imx27.c
rename to arch/arm/mach-imx/clock-imx27.c
index 0f0823c8b1707e9d8f86bbc77fb0320aa25395b8..5a1aa15c8a16140f17e75ea451b5441c9c413d10 100644 (file)
@@ -644,7 +644,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
        _REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
-       _REGISTER_CLOCK(NULL, "csi", csi_clk)
+       _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk1)
        _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk)
diff --git a/arch/arm/mach-imx/devices-imx1.h b/arch/arm/mach-imx/devices-imx1.h
new file mode 100644 (file)
index 0000000..a8d94f0
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/mx1.h>
+#include <mach/devices-common.h>
+
+#define imx1_add_i2c_imx(pdata)                \
+       imx_add_imx_i2c(0, MX1_I2C_BASE_ADDR, SZ_4K, MX1_INT_I2C, pdata)
+
+#define imx1_add_imx_uart0(pdata)      \
+       imx_add_imx_uart_3irq(0, MX1_UART1_BASE_ADDR, 0xd0, MX1_INT_UART1RX, MX1_INT_UART1TX, MX1_INT_UART1RTS, pdata)
+#define imx1_add_imx_uart1(pdata)      \
+       imx_add_imx_uart_3irq(0, MX1_UART2_BASE_ADDR, 0xd0, MX1_INT_UART2RX, MX1_INT_UART2TX, MX1_INT_UART2RTS, pdata)
diff --git a/arch/arm/mach-imx/devices-imx21.h b/arch/arm/mach-imx/devices-imx21.h
new file mode 100644 (file)
index 0000000..42788e9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/mx21.h>
+#include <mach/devices-common.h>
+
+#define imx21_add_i2c_imx(pdata)       \
+       imx_add_imx_i2c(0, MX2x_I2C_BASE_ADDR, SZ_4K, MX2x_INT_I2C, pdata)
+
+#define imx21_add_imx_uart0(pdata)     \
+       imx_add_imx_uart_1irq(0, MX21_UART1_BASE_ADDR, SZ_4K, MX21_INT_UART1, pdata)
+#define imx21_add_imx_uart1(pdata)     \
+       imx_add_imx_uart_1irq(1, MX21_UART2_BASE_ADDR, SZ_4K, MX21_INT_UART2, pdata)
+#define imx21_add_imx_uart2(pdata)     \
+       imx_add_imx_uart_1irq(2, MX21_UART3_BASE_ADDR, SZ_4K, MX21_INT_UART3, pdata)
+#define imx21_add_imx_uart3(pdata)     \
+       imx_add_imx_uart_1irq(3, MX21_UART4_BASE_ADDR, SZ_4K, MX21_INT_UART4, pdata)
+
+#define imx21_add_mxc_nand(pdata)      \
+       imx_add_mxc_nand_v1(MX21_NFC_BASE_ADDR, MX21_INT_NANDFC, pdata)
+
+#define imx21_add_spi_imx0(pdata)      \
+       imx_add_spi_imx(0, MX21_CSPI1_BASE_ADDR, SZ_4K, MX21_INT_CSPI1, pdata)
+#define imx21_add_spi_imx1(pdata)      \
+       imx_add_spi_imx(1, MX21_CSPI2_BASE_ADDR, SZ_4K, MX21_INT_CSPI2, pdata)
diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h
new file mode 100644 (file)
index 0000000..65e7bb7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/mx27.h>
+#include <mach/devices-common.h>
+
+#define imx27_add_i2c_imx0(pdata)      \
+       imx_add_imx_i2c(0, MX27_I2C1_BASE_ADDR, SZ_4K, MX27_INT_I2C1, pdata)
+#define imx27_add_i2c_imx1(pdata)      \
+       imx_add_imx_i2c(1, MX27_I2C2_BASE_ADDR, SZ_4K, MX27_INT_I2C2, pdata)
+
+#define imx27_add_imx_uart0(pdata)     \
+       imx_add_imx_uart_1irq(0, MX27_UART1_BASE_ADDR, SZ_4K, MX27_INT_UART1, pdata)
+#define imx27_add_imx_uart1(pdata)     \
+       imx_add_imx_uart_1irq(1, MX27_UART2_BASE_ADDR, SZ_4K, MX27_INT_UART2, pdata)
+#define imx27_add_imx_uart2(pdata)     \
+       imx_add_imx_uart_1irq(2, MX27_UART3_BASE_ADDR, SZ_4K, MX27_INT_UART3, pdata)
+#define imx27_add_imx_uart3(pdata)     \
+       imx_add_imx_uart_1irq(3, MX27_UART4_BASE_ADDR, SZ_4K, MX27_INT_UART4, pdata)
+#define imx27_add_imx_uart4(pdata)     \
+       imx_add_imx_uart_1irq(4, MX27_UART5_BASE_ADDR, SZ_4K, MX27_INT_UART5, pdata)
+#define imx27_add_imx_uart5(pdata)     \
+       imx_add_imx_uart_1irq(5, MX27_UART6_BASE_ADDR, SZ_4K, MX27_INT_UART6, pdata)
+
+#define imx27_add_mxc_nand(pdata)      \
+       imx_add_mxc_nand_v1(MX27_NFC_BASE_ADDR, MX27_INT_NANDFC, pdata)
+
+#define imx27_add_spi_imx0(pdata)      \
+       imx_add_spi_imx(0, MX27_CSPI1_BASE_ADDR, SZ_4K, MX27_INT_CSPI1, pdata)
+#define imx27_add_spi_imx1(pdata)      \
+       imx_add_spi_imx(1, MX27_CSPI2_BASE_ADDR, SZ_4K, MX27_INT_CSPI2, pdata)
+#define imx27_add_spi_imx2(pdata)      \
+       imx_add_spi_imx(2, MX27_CSPI3_BASE_ADDR, SZ_4K, MX27_INT_CSPI3, pdata)
similarity index 67%
rename from arch/arm/mach-mx2/devices.c
rename to arch/arm/mach-imx/devices.c
index a0aeb8a4adc19ef419a0a045ad3b882131597106..9c271a752b84da4e0380bf9fed2c86a5658a9640 100644 (file)
@@ -11,6 +11,9 @@
  *
  * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
+ * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (c) 2008 Darius Augulis <darius.augulis@teltonika.lt>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -32,6 +35,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/dma-mapping.h>
+#include <linux/serial.h>
 
 #include <mach/irqs.h>
 #include <mach/hardware.h>
 
 #include "devices.h"
 
-/*
- * SPI master controller
- *
- * - i.MX1: 2 channel (slighly different register setting)
- * - i.MX21: 2 channel
- * - i.MX27: 3 channel
- */
-#define DEFINE_IMX_SPI_DEVICE(n, baseaddr, irq)                                        \
-       static struct resource mxc_spi_resources ## n[] = {                     \
-               {                                                               \
-                       .start = baseaddr,                                      \
-                       .end = baseaddr + SZ_4K - 1,                            \
-                       .flags = IORESOURCE_MEM,                                \
-               }, {                                                            \
-                       .start = irq,                                           \
-                       .end = irq,                                             \
-                       .flags = IORESOURCE_IRQ,                                \
-               },                                                              \
-       };                                                                      \
-                                                                               \
-       struct platform_device mxc_spi_device ## n = {                          \
-               .name = "spi_imx",                                              \
-               .id = n,                                                        \
-               .num_resources = ARRAY_SIZE(mxc_spi_resources ## n),            \
-               .resource = mxc_spi_resources ## n,                             \
+#if defined(CONFIG_ARCH_MX1)
+static struct resource imx1_camera_resources[] = {
+       {
+               .start  = 0x00224000,
+               .end    = 0x00224010,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MX1_CSI_INT,
+               .end    = MX1_CSI_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 imx1_camera_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device imx1_camera_device = {
+       .name           = "mx1-camera",
+       .id             = 0, /* This is used to put cameras on this interface */
+       .dev            = {
+               .dma_mask = &imx1_camera_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .resource       = imx1_camera_resources,
+       .num_resources  = ARRAY_SIZE(imx1_camera_resources),
+};
+
+static struct resource imx_rtc_resources[] = {
+       {
+               .start  = 0x00204000,
+               .end    = 0x00204024,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MX1_RTC_INT,
+               .end    = MX1_RTC_INT,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_RTC_SAMINT,
+               .end    = MX1_RTC_SAMINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_rtc_device = {
+       .name           = "rtc-imx",
+       .id             = 0,
+       .resource       = imx_rtc_resources,
+       .num_resources  = ARRAY_SIZE(imx_rtc_resources),
+};
+
+static struct resource imx_wdt_resources[] = {
+       {
+               .start  = 0x00201000,
+               .end    = 0x00201008,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MX1_WDT_INT,
+               .end    = MX1_WDT_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_wdt_device = {
+       .name           = "imx-wdt",
+       .id             = 0,
+       .resource       = imx_wdt_resources,
+       .num_resources  = ARRAY_SIZE(imx_wdt_resources),
+};
+
+static struct resource imx_usb_resources[] = {
+       {
+               .start  = 0x00212000,
+               .end    = 0x00212148,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MX1_USBD_INT0,
+               .end    = MX1_USBD_INT0,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_USBD_INT1,
+               .end    = MX1_USBD_INT1,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_USBD_INT2,
+               .end    = MX1_USBD_INT2,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_USBD_INT3,
+               .end    = MX1_USBD_INT3,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_USBD_INT4,
+               .end    = MX1_USBD_INT4,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_USBD_INT5,
+               .end    = MX1_USBD_INT5,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = MX1_USBD_INT6,
+               .end    = MX1_USBD_INT6,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_usb_device = {
+       .name           = "imx_udc",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(imx_usb_resources),
+       .resource       = imx_usb_resources,
+};
+
+/* GPIO port description */
+static struct mxc_gpio_port imx_gpio_ports[] = {
+       {
+               .chip.label = "gpio-0",
+               .base = (void __iomem *)MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR),
+               .irq = MX1_GPIO_INT_PORTA,
+               .virtual_irq_start = MXC_GPIO_IRQ_START,
+       }, {
+               .chip.label = "gpio-1",
+               .base = (void __iomem *)MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR + 0x100),
+               .irq = MX1_GPIO_INT_PORTB,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32,
+       }, {
+               .chip.label = "gpio-2",
+               .base = (void __iomem *)MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR + 0x200),
+               .irq = MX1_GPIO_INT_PORTC,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 64,
+       }, {
+               .chip.label = "gpio-3",
+               .base = (void __iomem *)MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR + 0x300),
+               .irq = MX1_GPIO_INT_PORTD,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 96,
        }
+};
+
+int __init imx1_register_gpios(void)
+{
+       return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
+}
+#endif
 
-DEFINE_IMX_SPI_DEVICE(0, MX2x_CSPI1_BASE_ADDR, MX2x_INT_CSPI1);
-DEFINE_IMX_SPI_DEVICE(1, MX2x_CSPI2_BASE_ADDR, MX2x_INT_CSPI2);
+#if defined(CONFIG_MACH_MX21) || defined(CONFIG_MACH_MX27)
 
 #ifdef CONFIG_MACH_MX27
-DEFINE_IMX_SPI_DEVICE(2, MX27_CSPI3_BASE_ADDR, MX27_INT_CSPI3);
+static struct resource mx27_camera_resources[] = {
+       {
+              .start = MX27_CSI_BASE_ADDR,
+              .end = MX27_CSI_BASE_ADDR + 0x1f,
+              .flags = IORESOURCE_MEM,
+       }, {
+              .start = MX27_EMMA_PRP_BASE_ADDR,
+              .end = MX27_EMMA_PRP_BASE_ADDR + 0x1f,
+              .flags = IORESOURCE_MEM,
+       }, {
+              .start = MX27_INT_CSI,
+              .end = MX27_INT_CSI,
+              .flags = IORESOURCE_IRQ,
+       },{
+              .start = MX27_INT_EMMAPRP,
+              .end = MX27_INT_EMMAPRP,
+              .flags = IORESOURCE_IRQ,
+       },
+};
+struct platform_device mx27_camera_device = {
+       .name = "mx2-camera",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mx27_camera_resources),
+       .resource = mx27_camera_resources,
+       .dev = {
+               .coherent_dma_mask = 0xffffffff,
+       },
+};
 #endif
 
 /*
@@ -140,34 +285,6 @@ struct platform_device mxc_w1_master_device = {
        .resource = mxc_w1_master_resources,
 };
 
-#define DEFINE_MXC_NAND_DEVICE(pfx, baseaddr, irq)                     \
-       static struct resource pfx ## _nand_resources[] = {             \
-               {                                                       \
-                       .start = baseaddr,                              \
-                       .end = baseaddr + SZ_4K - 1,                    \
-                       .flags = IORESOURCE_MEM,                        \
-               }, {                                                    \
-                       .start = irq,                                   \
-                       .end = irq,                                     \
-                       .flags = IORESOURCE_IRQ,                        \
-               },                                                      \
-       };                                                              \
-                                                                       \
-       struct platform_device pfx ## _nand_device = {                  \
-               .name = "mxc_nand",                                     \
-               .id = 0,                                                \
-               .num_resources = ARRAY_SIZE(pfx ## _nand_resources),    \
-               .resource = pfx ## _nand_resources,                     \
-       }
-
-#ifdef CONFIG_MACH_MX21
-DEFINE_MXC_NAND_DEVICE(imx21, MX21_NFC_BASE_ADDR, MX21_INT_NANDFC);
-#endif
-
-#ifdef CONFIG_MACH_MX27
-DEFINE_MXC_NAND_DEVICE(imx27, MX27_NFC_BASE_ADDR, MX27_INT_NANDFC);
-#endif
-
 /*
  * lcdc:
  * - i.MX1: the basic controller
@@ -218,32 +335,6 @@ struct platform_device mxc_fec_device = {
 };
 #endif
 
-#define DEFINE_IMX_I2C_DEVICE(n, baseaddr, irq)                                \
-       static struct resource mxc_i2c_resources ## n[] = {             \
-               {                                                       \
-                       .start = baseaddr,                              \
-                       .end = baseaddr + SZ_4K - 1,                    \
-                       .flags = IORESOURCE_MEM,                        \
-               }, {                                                    \
-                       .start = irq,                                   \
-                       .end = irq,                                     \
-                       .flags = IORESOURCE_IRQ,                        \
-               }                                                       \
-       };                                                              \
-                                                                       \
-       struct platform_device mxc_i2c_device ## n = {                  \
-               .name = "imx-i2c",                                      \
-               .id = n,                                                \
-               .num_resources = ARRAY_SIZE(mxc_i2c_resources ## n),    \
-               .resource = mxc_i2c_resources ## n,                     \
-       }
-
-DEFINE_IMX_I2C_DEVICE(0, MX2x_I2C_BASE_ADDR, MX2x_INT_I2C);
-
-#ifdef CONFIG_MACH_MX27
-DEFINE_IMX_I2C_DEVICE(1, MX27_I2C2_BASE_ADDR, MX27_INT_I2C2);
-#endif
-
 static struct resource mxc_pwm_resources[] = {
        {
                .start = MX2x_PWM_BASE_ADDR,
@@ -454,26 +545,21 @@ DEFINE_IMX_SSI_DEVICE(1, 2, MX2x_SSI1_BASE_ADDR, MX2x_INT_SSI1);
 
 #ifdef CONFIG_MACH_MX21
 DEFINE_MXC_GPIO_PORTS(MX21, imx21);
+
+int __init imx21_register_gpios(void)
+{
+       return mxc_gpio_init(imx21_gpio_ports, ARRAY_SIZE(imx21_gpio_ports));
+}
 #endif
 
 #ifdef CONFIG_MACH_MX27
 DEFINE_MXC_GPIO_PORTS(MX27, imx27);
-#endif
 
-int __init mxc_register_gpios(void)
+int __init imx27_register_gpios(void)
 {
-#ifdef CONFIG_MACH_MX21
-       if (cpu_is_mx21())
-               return mxc_gpio_init(imx21_gpio_ports, ARRAY_SIZE(imx21_gpio_ports));
-       else
-#endif
-#ifdef CONFIG_MACH_MX27
-       if (cpu_is_mx27())
-               return mxc_gpio_init(imx27_gpio_ports, ARRAY_SIZE(imx27_gpio_ports));
-       else
-#endif
-               return 0;
+       return mxc_gpio_init(imx27_gpio_ports, ARRAY_SIZE(imx27_gpio_ports));
 }
+#endif
 
 #ifdef CONFIG_MACH_MX21
 static struct resource mx21_usbhc_resources[] = {
@@ -501,3 +587,23 @@ struct platform_device mx21_usbhc_device = {
 };
 #endif
 
+static struct resource imx_kpp_resources[] = {
+       {
+               .start  = MX2x_KPP_BASE_ADDR,
+               .end    = MX2x_KPP_BASE_ADDR + 0xf,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = MX2x_INT_KPP,
+               .end    = MX2x_INT_KPP,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_kpp_device = {
+       .name = "imx-keypad",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(imx_kpp_resources),
+       .resource = imx_kpp_resources,
+};
+
+#endif
similarity index 54%
rename from arch/arm/mach-mx2/devices.h
rename to arch/arm/mach-imx/devices.h
index 84ed51380174ebd6cadaef60f19245ede9df7782..efd4527506a5e661da74c95e9d756c0674ca3d33 100644 (file)
@@ -1,3 +1,11 @@
+#ifdef CONFIG_ARCH_MX1
+extern struct platform_device imx1_camera_device;
+extern struct platform_device imx_rtc_device;
+extern struct platform_device imx_wdt_device;
+extern struct platform_device imx_usb_device;
+#endif
+
+#if defined(CONFIG_MACH_MX21) || defined(CONFIG_MACH_MX27)
 extern struct platform_device mxc_gpt1;
 extern struct platform_device mxc_gpt2;
 #ifdef CONFIG_MACH_MX27
@@ -6,37 +14,19 @@ extern struct platform_device mxc_gpt4;
 extern struct platform_device mxc_gpt5;
 #endif
 extern struct platform_device mxc_wdt;
-extern struct platform_device mxc_uart_device0;
-extern struct platform_device mxc_uart_device1;
-extern struct platform_device mxc_uart_device2;
-extern struct platform_device mxc_uart_device3;
-extern struct platform_device mxc_uart_device4;
-extern struct platform_device mxc_uart_device5;
 extern struct platform_device mxc_w1_master_device;
-#ifdef CONFIG_MACH_MX21
-extern struct platform_device imx21_nand_device;
-#endif
-#ifdef CONFIG_MACH_MX27
-extern struct platform_device imx27_nand_device;
-#endif
 extern struct platform_device mxc_fb_device;
 extern struct platform_device mxc_fec_device;
 extern struct platform_device mxc_pwm_device;
-extern struct platform_device mxc_i2c_device0;
-#ifdef CONFIG_MACH_MX27
-extern struct platform_device mxc_i2c_device1;
-#endif
 extern struct platform_device mxc_sdhc_device0;
 extern struct platform_device mxc_sdhc_device1;
 extern struct platform_device mxc_otg_udc_device;
+extern struct platform_device mx27_camera_device;
 extern struct platform_device mxc_otg_host;
 extern struct platform_device mxc_usbh1;
 extern struct platform_device mxc_usbh2;
-extern struct platform_device mxc_spi_device0;
-extern struct platform_device mxc_spi_device1;
-#ifdef CONFIG_MACH_MX27
-extern struct platform_device mxc_spi_device2;
-#endif
 extern struct platform_device mx21_usbhc_device;
 extern struct platform_device imx_ssi_device0;
 extern struct platform_device imx_ssi_device1;
+extern struct platform_device imx_kpp_device;
+#endif
similarity index 99%
rename from arch/arm/plat-mxc/dma-mx1-mx2.c
rename to arch/arm/mach-imx/dma-v1.c
index e16014b0d13c817fe56e66fcb71a588ee0abf72e..fd1d9197d06ef66f9b5e5a3d95d3a825510f47a5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/plat-mxc/dma-mx1-mx2.c
+ *  linux/arch/arm/plat-mxc/dma-v1.c
  *
  *  i.MX DMA registration and IRQ dispatching
  *
@@ -34,7 +34,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <mach/dma-mx1-mx2.h>
+#include <mach/dma-v1.h>
 
 #define DMA_DCR     0x00               /* Control Register */
 #define DMA_DISR    0x04               /* Interrupt status Register */
similarity index 52%
rename from arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c
rename to arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
index f3b169d5245fcdf7f751c896ad693073bba31087..4edc5f43920109011d6e8f8fd64234e3fe3cb992 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Eric Benard - eric@eukrea.com
+ * Copyright (C) 2009-2010 Eric Benard - eric@eukrea.com
  *
  * Based on pcm970-baseboard.c which is :
  * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
@@ -24,6 +24,9 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/backlight.h>
+#include <video/platform_lcd.h>
+#include <linux/input/matrix_keypad.h>
 
 #include <asm/mach/arch.h>
 
 #include <mach/imxfb.h>
 #include <mach/hardware.h>
 #include <mach/mmc.h>
-#include <mach/imx-uart.h>
+#include <mach/spi.h>
+#include <mach/ssi.h>
+#include <mach/audmux.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 static int eukrea_mbimx27_pins[] = {
@@ -48,10 +54,12 @@ static int eukrea_mbimx27_pins[] = {
        PE10_PF_UART3_CTS,
        PE11_PF_UART3_RTS,
        /* UART4 */
+#if !defined(MACH_EUKREA_CPUIMX27_USEUART4)
        PB26_AF_UART4_RTS,
        PB28_AF_UART4_TXD,
        PB29_AF_UART4_CTS,
        PB31_AF_UART4_RXD,
+#endif
        /* SDHC1*/
        PE18_PF_SD1_D0,
        PE19_PF_SD1_D1,
@@ -84,10 +92,29 @@ static int eukrea_mbimx27_pins[] = {
        PA30_PF_CONTRAST,
        PA31_PF_OE_ACD,
        /* SPI1 */
-       PD28_PF_CSPI1_SS0,
        PD29_PF_CSPI1_SCLK,
        PD30_PF_CSPI1_MISO,
        PD31_PF_CSPI1_MOSI,
+       /* SSI4 */
+#if defined(CONFIG_SND_SOC_EUKREA_TLV320) \
+       || defined(CONFIG_SND_SOC_EUKREA_TLV320_MODULE)
+       PC16_PF_SSI4_FS,
+       PC17_PF_SSI4_RXD | GPIO_PUEN,
+       PC18_PF_SSI4_TXD | GPIO_PUEN,
+       PC19_PF_SSI4_CLK,
+#endif
+};
+
+static const uint32_t eukrea_mbimx27_keymap[] = {
+       KEY(0, 0, KEY_UP),
+       KEY(0, 1, KEY_DOWN),
+       KEY(1, 0, KEY_RIGHT),
+       KEY(1, 1, KEY_LEFT),
+};
+
+static struct matrix_keymap_data eukrea_mbimx27_keymap_data = {
+       .keymap         = eukrea_mbimx27_keymap,
+       .keymap_size    = ARRAY_SIZE(eukrea_mbimx27_keymap),
 };
 
 static struct gpio_led gpio_leds[] = {
@@ -103,12 +130,6 @@ static struct gpio_led gpio_leds[] = {
                .active_low             = 1,
                .gpio                   = GPIO_PORTF | 19,
        },
-       {
-               .name                   = "backlight",
-               .default_trigger        = "backlight",
-               .active_low             = 0,
-               .gpio                   = GPIO_PORTE | 5,
-       },
 };
 
 static struct gpio_led_platform_data gpio_led_info = {
@@ -127,7 +148,7 @@ static struct platform_device leds_gpio = {
 static struct imx_fb_videomode eukrea_mbimx27_modes[] = {
        {
                .mode = {
-                       .name           = "CMO-QGVA",
+                       .name           = "CMO-QVGA",
                        .refresh        = 60,
                        .xres           = 320,
                        .yres           = 240,
@@ -141,6 +162,38 @@ static struct imx_fb_videomode eukrea_mbimx27_modes[] = {
                },
                .pcr            = 0xFAD08B80,
                .bpp            = 16,
+       }, {
+               .mode = {
+                       .name           = "DVI-VGA",
+                       .refresh        = 60,
+                       .xres           = 640,
+                       .yres           = 480,
+                       .pixclock       = 32000,
+                       .hsync_len      = 1,
+                       .left_margin    = 35,
+                       .right_margin   = 0,
+                       .vsync_len      = 1,
+                       .upper_margin   = 7,
+                       .lower_margin   = 0,
+               },
+               .pcr            = 0xFA208B80,
+               .bpp            = 16,
+       }, {
+               .mode = {
+                       .name           = "DVI-SVGA",
+                       .refresh        = 60,
+                       .xres           = 800,
+                       .yres           = 600,
+                       .pixclock       = 25000,
+                       .hsync_len      = 1,
+                       .left_margin    = 35,
+                       .right_margin   = 0,
+                       .vsync_len      = 1,
+                       .upper_margin   = 7,
+                       .lower_margin   = 0,
+               },
+               .pcr            = 0xFA208B80,
+               .bpp            = 16,
        },
 };
 
@@ -153,16 +206,52 @@ static struct imx_fb_platform_data eukrea_mbimx27_fb_data = {
        .dmacr          = 0x00040060,
 };
 
-static struct imxuart_platform_data uart_pdata[] = {
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
-       },
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
+static void eukrea_mbimx27_bl_set_intensity(int intensity)
+{
+       if (intensity)
+               gpio_direction_output(GPIO_PORTE | 5, 1);
+       else
+               gpio_direction_output(GPIO_PORTE | 5, 0);
+}
+
+static struct generic_bl_info eukrea_mbimx27_bl_info = {
+       .name                   = "eukrea_mbimx27-bl",
+       .max_intensity          = 0xff,
+       .default_intensity      = 0xff,
+       .set_bl_intensity       = eukrea_mbimx27_bl_set_intensity,
+};
+
+static struct platform_device eukrea_mbimx27_bl_dev = {
+       .name                   = "generic-bl",
+       .id                     = 1,
+       .dev = {
+               .platform_data  = &eukrea_mbimx27_bl_info,
        },
 };
 
-#if defined(CONFIG_TOUCHSCREEN_ADS7846)
+static void eukrea_mbimx27_lcd_power_set(struct plat_lcd_data *pd,
+                                  unsigned int power)
+{
+       if (power)
+               gpio_direction_output(GPIO_PORTA | 25, 1);
+       else
+               gpio_direction_output(GPIO_PORTA | 25, 0);
+}
+
+static struct plat_lcd_data eukrea_mbimx27_lcd_power_data = {
+       .set_power              = eukrea_mbimx27_lcd_power_set,
+};
+
+static struct platform_device eukrea_mbimx27_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.platform_data      = &eukrea_mbimx27_lcd_power_data,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) \
        || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 
 #define ADS7846_PENDOWN (GPIO_PORTD | 25)
@@ -173,7 +262,6 @@ static void ads7846_dev_init(void)
                printk(KERN_ERR "can't get ads746 pen down GPIO\n");
                return;
        }
-
        gpio_direction_input(ADS7846_PENDOWN);
 }
 
@@ -186,7 +274,9 @@ static struct ads7846_platform_data ads7846_config __initdata = {
        .get_pendown_state      = ads7846_get_pendown_state,
        .keep_vref_on           = 1,
 };
+#endif
 
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
 static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
        [0] = {
                .modalias       = "ads7846",
@@ -201,16 +291,30 @@ static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
 
 static int eukrea_mbimx27_spi_cs[] = {GPIO_PORTD | 28};
 
-static struct spi_imx_master eukrea_mbimx27_spi_0_data = {
+static const struct spi_imx_master eukrea_mbimx27_spi0_data __initconst = {
        .chipselect     = eukrea_mbimx27_spi_cs,
        .num_chipselect = ARRAY_SIZE(eukrea_mbimx27_spi_cs),
 };
 #endif
 
+static struct i2c_board_info eukrea_mbimx27_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       },
+};
+
 static struct platform_device *platform_devices[] __initdata = {
        &leds_gpio,
 };
 
+static struct imxmmc_platform_data sdhc_pdata = {
+       .dat3_card_detect = 1,
+};
+
+struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata = {
+       .flags = IMX_SSI_DMA | IMX_SSI_USE_I2S_SLAVE,
+};
+
 /*
  * system init for baseboard usage. Will be called by cpuimx27 init.
  *
@@ -222,21 +326,52 @@ void __init eukrea_mbimx27_baseboard_init(void)
        mxc_gpio_setup_multiple_pins(eukrea_mbimx27_pins,
                ARRAY_SIZE(eukrea_mbimx27_pins), "MBIMX27");
 
-       mxc_register_device(&mxc_uart_device1, &uart_pdata[0]);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata[1]);
+#if defined(CONFIG_SND_SOC_EUKREA_TLV320) \
+       || defined(CONFIG_SND_SOC_EUKREA_TLV320_MODULE)
+       /* SSI unit master I2S codec connected to SSI_PINS_4*/
+       mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+                       MXC_AUDMUX_V1_PCR_SYN |
+                       MXC_AUDMUX_V1_PCR_TFSDIR |
+                       MXC_AUDMUX_V1_PCR_TCLKDIR |
+                       MXC_AUDMUX_V1_PCR_RFSDIR |
+                       MXC_AUDMUX_V1_PCR_RCLKDIR |
+                       MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+                       MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+                       MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
+       );
+       mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
+                       MXC_AUDMUX_V1_PCR_SYN |
+                       MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+       );
+#endif
+
+       imx27_add_imx_uart1(&uart_pdata);
+       imx27_add_imx_uart2(&uart_pdata);
+#if !defined(MACH_EUKREA_CPUIMX27_USEUART4)
+       imx27_add_imx_uart3(&uart_pdata);
+#endif
 
        mxc_register_device(&mxc_fb_device, &eukrea_mbimx27_fb_data);
-       mxc_register_device(&mxc_sdhc_device0, NULL);
+       mxc_register_device(&mxc_sdhc_device0, &sdhc_pdata);
 
-#if defined(CONFIG_TOUCHSCREEN_ADS7846)
+       i2c_register_board_info(0, eukrea_mbimx27_i2c_devices,
+                               ARRAY_SIZE(eukrea_mbimx27_i2c_devices));
+
+       mxc_register_device(&imx_ssi_device0, &eukrea_mbimx27_ssi_pdata);
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) \
        || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-       /* SPI and ADS7846 Touchscreen controler init */
-       mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
+       /* ADS7846 Touchscreen controller init */
        mxc_gpio_mode(GPIO_PORTD | 25 | GPIO_GPIO | GPIO_IN);
-       mxc_register_device(&mxc_spi_device0, &eukrea_mbimx27_spi_0_data);
+       ads7846_dev_init();
+#endif
+
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
+       /* SPI_CS0 init */
+       mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
+       imx27_add_spi_imx0(&eukrea_mbimx27_spi0_data);
        spi_register_board_info(eukrea_mbimx27_spi_board_info,
                        ARRAY_SIZE(eukrea_mbimx27_spi_board_info));
-       ads7846_dev_init();
 #endif
 
        /* Leds configuration */
@@ -244,6 +379,14 @@ void __init eukrea_mbimx27_baseboard_init(void)
        mxc_gpio_mode(GPIO_PORTF | 19 | GPIO_GPIO | GPIO_OUT);
        /* Backlight */
        mxc_gpio_mode(GPIO_PORTE | 5 | GPIO_GPIO | GPIO_OUT);
+       gpio_request(GPIO_PORTE | 5, "backlight");
+       platform_device_register(&eukrea_mbimx27_bl_dev);
+       /* LCD Reset */
+       mxc_gpio_mode(GPIO_PORTA | 25 | GPIO_GPIO | GPIO_OUT);
+       gpio_request(GPIO_PORTA | 25, "lcd_enable");
+       platform_device_register(&eukrea_mbimx27_lcd_powerdev);
+
+       mxc_register_device(&imx_kpp_device, &eukrea_mbimx27_keymap_data);
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
diff --git a/arch/arm/mach-imx/include/mach/dma-mx1-mx2.h b/arch/arm/mach-imx/include/mach/dma-mx1-mx2.h
new file mode 100644 (file)
index 0000000..df5f522
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __MACH_DMA_MX1_MX2_H__
+#define __MACH_DMA_MX1_MX2_H__
+/*
+ * Don't use this header in new code, it will go away when all users are
+ * converted to mach/dma-v1.h
+ */
+
+#include <mach/dma-v1.h>
+
+#endif /* ifndef __MACH_DMA_MX1_MX2_H__ */
similarity index 93%
rename from arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
rename to arch/arm/mach-imx/include/mach/dma-v1.h
index 7c4870bd5a2144e39697501ce4b85e42e1e36459..287431cc13e59d32f4e592d6e1d58eb247c378b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
+ *  linux/arch/arm/mach-imx/include/mach/dma-v1.h
  *
  *  i.MX DMA registration and IRQ dispatching
  *
  * MA 02110-1301, USA.
  */
 
-#ifndef __ASM_ARCH_MXC_DMA_H
-#define __ASM_ARCH_MXC_DMA_H
+#ifndef __MACH_DMA_V1_H__
+#define __MACH_DMA_V1_H__
+
+#define imx_has_dma_v1()       (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
 
 #define IMX_DMA_CHANNELS  16
 
@@ -102,4 +104,4 @@ enum imx_dma_prio {
 
 int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio);
 
-#endif /* _ASM_ARCH_MXC_DMA_H */
+#endif /* __MACH_DMA_V1_H__ */
similarity index 66%
rename from arch/arm/mach-mx2/mach-cpuimx27.c
rename to arch/arm/mach-imx/mach-cpuimx27.c
index 1f616dcaabc9bbf1089438c29e81bc57d0140dea..575ff1ae85a738f84cf48720d19e850b96caa0e5 100644 (file)
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/fsl_devices.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
 
-#include <mach/board-eukrea_cpuimx27.h>
+#include <mach/eukrea-baseboards.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/i2c.h>
 #include <mach/iomux-mx27.h>
-#include <mach/imx-uart.h>
 #include <mach/mxc_nand.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 static int eukrea_cpuimx27_pins[] = {
@@ -49,10 +53,12 @@ static int eukrea_cpuimx27_pins[] = {
        PE14_PF_UART1_CTS,
        PE15_PF_UART1_RTS,
        /* UART4 */
+#if defined(MACH_EUKREA_CPUIMX27_USEUART4)
        PB26_AF_UART4_RTS,
        PB28_AF_UART4_TXD,
        PB29_AF_UART4_CTS,
        PB31_AF_UART4_RXD,
+#endif
        /* FEC */
        PD0_AIN_FEC_TXD0,
        PD1_AIN_FEC_TXD1,
@@ -76,19 +82,47 @@ static int eukrea_cpuimx27_pins[] = {
        PD17_PF_I2C_DATA,
        PD18_PF_I2C_CLK,
        /* SDHC2 */
+#if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
        PB4_PF_SD2_D0,
        PB5_PF_SD2_D1,
        PB6_PF_SD2_D2,
        PB7_PF_SD2_D3,
        PB8_PF_SD2_CMD,
        PB9_PF_SD2_CLK,
+#endif
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        /* Quad UART's IRQ */
-       GPIO_PORTD | 22 | GPIO_GPIO | GPIO_IN,
-       GPIO_PORTD | 23 | GPIO_GPIO | GPIO_IN,
-       GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN,
-       GPIO_PORTD | 30 | GPIO_GPIO | GPIO_IN,
+       GPIO_PORTB | 22 | GPIO_GPIO | GPIO_IN,
+       GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN,
+       GPIO_PORTB | 27 | GPIO_GPIO | GPIO_IN,
+       GPIO_PORTB | 30 | GPIO_GPIO | GPIO_IN,
 #endif
+       /* OTG */
+       PC7_PF_USBOTG_DATA5,
+       PC8_PF_USBOTG_DATA6,
+       PC9_PF_USBOTG_DATA0,
+       PC10_PF_USBOTG_DATA2,
+       PC11_PF_USBOTG_DATA1,
+       PC12_PF_USBOTG_DATA4,
+       PC13_PF_USBOTG_DATA3,
+       PE0_PF_USBOTG_NXT,
+       PE1_PF_USBOTG_STP,
+       PE2_PF_USBOTG_DIR,
+       PE24_PF_USBOTG_CLK,
+       PE25_PF_USBOTG_DATA7,
+       /* USBH2 */
+       PA0_PF_USBH2_CLK,
+       PA1_PF_USBH2_DIR,
+       PA2_PF_USBH2_DATA7,
+       PA3_PF_USBH2_NXT,
+       PA4_PF_USBH2_STP,
+       PD19_AF_USBH2_DATA4,
+       PD20_AF_USBH2_DATA3,
+       PD21_AF_USBH2_DATA6,
+       PD22_AF_USBH2_DATA0,
+       PD23_AF_USBH2_DATA2,
+       PD24_AF_USBH2_DATA1,
+       PD26_AF_USBH2_DATA5,
 };
 
 static struct physmap_flash_data eukrea_cpuimx27_flash_data = {
@@ -111,15 +145,12 @@ static struct platform_device eukrea_cpuimx27_nor_mtd_device = {
        .resource = &eukrea_cpuimx27_flash_resource,
 };
 
-static struct imxuart_platform_data uart_pdata[] = {
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       },
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct mxc_nand_platform_data eukrea_cpuimx27_nand_board_info = {
+static const struct mxc_nand_platform_data
+cpuimx27_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
@@ -127,9 +158,11 @@ static struct mxc_nand_platform_data eukrea_cpuimx27_nand_board_info = {
 static struct platform_device *platform_devices[] __initdata = {
        &eukrea_cpuimx27_nor_mtd_device,
        &mxc_fec_device,
+       &mxc_wdt,
+       &mxc_w1_master_device,
 };
 
-static struct imxi2c_platform_data eukrea_cpuimx27_i2c_1_data = {
+static const struct imxi2c_platform_data cpuimx27_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -182,34 +215,83 @@ static struct platform_device serial_device = {
 };
 #endif
 
+#if defined(CONFIG_USB_ULPI)
+static struct mxc_usbh_platform_data otg_pdata = {
+       .portsc = MXC_EHCI_MODE_ULPI,
+       .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
+};
+
+static struct mxc_usbh_platform_data usbh2_pdata = {
+       .portsc = MXC_EHCI_MODE_ULPI,
+       .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
+};
+#endif
+
+static struct fsl_usb2_platform_data otg_device_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx27_otg_mode(char *options)
+{
+       if (!strcmp(options, "host"))
+               otg_mode_host = 1;
+       else if (!strcmp(options, "device"))
+               otg_mode_host = 0;
+       else
+               pr_info("otg_mode neither \"host\" nor \"device\". "
+                       "Defaulting to device\n");
+       return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx27_otg_mode);
+
 static void __init eukrea_cpuimx27_init(void)
 {
        mxc_gpio_setup_multiple_pins(eukrea_cpuimx27_pins,
                ARRAY_SIZE(eukrea_cpuimx27_pins), "CPUIMX27");
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
+       imx27_add_imx_uart0(&uart_pdata);
 
-       mxc_register_device(&imx27_nand_device,
-                       &eukrea_cpuimx27_nand_board_info);
+       imx27_add_mxc_nand(&cpuimx27_nand_board_info);
 
        i2c_register_board_info(0, eukrea_cpuimx27_i2c_devices,
                                ARRAY_SIZE(eukrea_cpuimx27_i2c_devices));
 
-       mxc_register_device(&mxc_i2c_device0, &eukrea_cpuimx27_i2c_1_data);
+       imx27_add_i2c_imx1(&cpuimx27_i2c1_data);
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 #if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
        /* SDHC2 can be used for Wifi */
        mxc_register_device(&mxc_sdhc_device1, NULL);
+#endif
+#if defined(MACH_EUKREA_CPUIMX27_USEUART4)
        /* in which case UART4 is also used for Bluetooth */
-       mxc_register_device(&mxc_uart_device3, &uart_pdata[1]);
+       imx27_add_imx_uart3(&uart_pdata);
 #endif
 
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        platform_device_register(&serial_device);
 #endif
 
+#if defined(CONFIG_USB_ULPI)
+       if (otg_mode_host) {
+               otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                               USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+               mxc_register_device(&mxc_otg_host, &otg_pdata);
+       }
+
+       usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                               USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+       mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+#endif
+       if (!otg_mode_host)
+               mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
+
 #ifdef CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD
        eukrea_mbimx27_baseboard_init();
 #endif
similarity index 86%
rename from arch/arm/mach-mx2/mach-imx27lite.c
rename to arch/arm/mach-imx/mach-imx27lite.c
index b5710bf18b9684d7f65682e52060aa16b4f48b1b..22a2b5d912136590addc1fcd05f32d905b1af8d0 100644 (file)
  * 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 <asm/mach/map.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx27.h>
-#include <mach/board-mx27lite.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 static unsigned int mx27lite_pins[] = {
@@ -59,7 +54,7 @@ static unsigned int mx27lite_pins[] = {
        PF23_AIN_FEC_TX_EN,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -71,7 +66,7 @@ static void __init mx27lite_init(void)
 {
        mxc_gpio_setup_multiple_pins(mx27lite_pins, ARRAY_SIZE(mx27lite_pins),
                "imx27lite");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx27_add_imx_uart0(&uart_pdata);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
 
similarity index 81%
rename from arch/arm/mach-mx1/mach-mx1ads.c
rename to arch/arm/mach-imx/mach-mx1ads.c
index 51f3cfd83db2ee4615d68824797db1b755a61fb1..77a760cfadc0260dba05324318e00e3d5605defd 100644 (file)
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/i2c.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx1.h>
 #include <mach/irqs.h>
 
+#include "devices-imx1.h"
 #include "devices.h"
 
 static int mx1ads_pins[] = {
@@ -58,12 +58,12 @@ static int mx1ads_pins[] = {
  * UARTs platform data
  */
 
-static struct imxuart_platform_data uart_pdata[] = {
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       },
+static const struct imxuart_platform_data uart0_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+       
+static const struct imxuart_platform_data uart1_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
 };
 
 /*
@@ -75,8 +75,8 @@ static struct physmap_flash_data mx1ads_flash_data = {
 };
 
 static struct resource flash_resource = {
-       .start  = IMX_CS0_PHYS,
-       .end    = IMX_CS0_PHYS + SZ_32M - 1,
+       .start  = MX1_CS0_PHYS,
+       .end    = MX1_CS0_PHYS + SZ_32M - 1,
        .flags  = IORESOURCE_MEM,
 };
 
@@ -98,7 +98,7 @@ static struct pcf857x_platform_data pcf857x_data[] = {
        }
 };
 
-static struct imxi2c_platform_data mx1ads_i2c_data = {
+static const struct imxi2c_platform_data mx1ads_i2c_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -121,8 +121,8 @@ static void __init mx1ads_init(void)
                ARRAY_SIZE(mx1ads_pins), "mx1ads");
 
        /* UART */
-       mxc_register_device(&imx_uart1_device, &uart_pdata[0]);
-       mxc_register_device(&imx_uart2_device, &uart_pdata[1]);
+       imx1_add_imx_uart0(&uart0_pdata);
+       imx1_add_imx_uart1(&uart1_pdata);
 
        /* Physmap flash */
        mxc_register_device(&flash_device, &mx1ads_flash_data);
@@ -131,7 +131,7 @@ static void __init mx1ads_init(void)
        i2c_register_board_info(0, mx1ads_i2c_devices,
                                ARRAY_SIZE(mx1ads_i2c_devices));
 
-       mxc_register_device(&imx_i2c_device, &mx1ads_i2c_data);
+       imx1_add_i2c_imx(&mx1ads_i2c_data);
 }
 
 static void __init mx1ads_timer_init(void)
@@ -145,8 +145,8 @@ struct sys_timer mx1ads_timer = {
 
 MACHINE_START(MX1ADS, "Freescale MX1ADS")
        /* Maintainer: Sascha Hauer, Pengutronix */
-       .phys_io        = IMX_IO_PHYS,
-       .io_pg_offst    = (IMX_IO_BASE >> 18) & 0xfffc,
+       .phys_io        = MX1_IO_BASE_ADDR,
+       .io_pg_offst    = (MX1_IO_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX1_PHYS_OFFSET + 0x100,
        .map_io         = mx1_map_io,
        .init_irq       = mx1_init_irq,
@@ -155,8 +155,8 @@ MACHINE_START(MX1ADS, "Freescale MX1ADS")
 MACHINE_END
 
 MACHINE_START(MXLADS, "Freescale MXLADS")
-       .phys_io        = IMX_IO_PHYS,
-       .io_pg_offst    = (IMX_IO_BASE >> 18) & 0xfffc,
+       .phys_io        = MX1_IO_BASE_ADDR,
+       .io_pg_offst    = (MX1_IO_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX1_PHYS_OFFSET + 0x100,
        .map_io         = mx1_map_io,
        .init_irq       = mx1_init_irq,
similarity index 77%
rename from arch/arm/mach-mx2/mach-mx21ads.c
rename to arch/arm/mach-imx/mach-mx21ads.c
index 113e58d7cb4025962f0eebd85ac3fbc5b63dc398..96d7f8189f3253a0feb79d0278c51abbc3e4e5bf 100644 (file)
  * 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 <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
-#include <mach/imx-uart.h>
 #include <mach/imxfb.h>
 #include <mach/iomux-mx21.h>
 #include <mach/mxc_nand.h>
 #include <mach/mmc.h>
-#include <mach/board-mx21ads.h>
 
+#include "devices-imx21.h"
 #include "devices.h"
 
+/*
+ * Memory-mapped I/O on MX21ADS base board
+ */
+#define MX21ADS_MMIO_BASE_ADDR   0xf5000000
+#define MX21ADS_MMIO_SIZE        SZ_16M
+
+#define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
+               (MX21ADS_MMIO_BASE_ADDR + (offset))
+
+#define MX21ADS_CS8900A_IRQ         IRQ_GPIOE(11)
+#define MX21ADS_CS8900A_IOBASE_REG  MX21ADS_REG_ADDR(0x000000)
+#define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000)
+#define MX21ADS_VERSION_REG         MX21ADS_REG_ADDR(0x400000)
+#define MX21ADS_IO_REG              MX21ADS_REG_ADDR(0x800000)
+
+/* MX21ADS_IO_REG bit definitions */
+#define MX21ADS_IO_SD_WP        0x0001 /* read */
+#define MX21ADS_IO_TP6          0x0001 /* write */
+#define MX21ADS_IO_SW_SEL       0x0002 /* read */
+#define MX21ADS_IO_TP7          0x0002 /* write */
+#define MX21ADS_IO_RESET_E_UART 0x0004
+#define MX21ADS_IO_RESET_BASE   0x0008
+#define MX21ADS_IO_CSI_CTL2     0x0010
+#define MX21ADS_IO_CSI_CTL1     0x0020
+#define MX21ADS_IO_CSI_CTL0     0x0040
+#define MX21ADS_IO_UART1_EN     0x0080
+#define MX21ADS_IO_UART4_EN     0x0100
+#define MX21ADS_IO_LCDON        0x0200
+#define MX21ADS_IO_IRDA_EN      0x0400
+#define MX21ADS_IO_IRDA_FIR_SEL 0x0800
+#define MX21ADS_IO_IRDA_MD0_B   0x1000
+#define MX21ADS_IO_IRDA_MD1     0x2000
+#define MX21ADS_IO_LED4_ON      0x4000
+#define MX21ADS_IO_LED3_ON      0x8000
+
 static unsigned int mx21ads_pins[] = {
 
        /* CS8900A */
@@ -133,14 +163,13 @@ static struct platform_device mx21ads_nor_mtd_device = {
        .resource = &mx21ads_flash_resource,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata_rts __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct imxuart_platform_data uart_norts_pdata = {
+static const struct imxuart_platform_data uart_pdata_norts __initconst = {
 };
 
-
 static int mx21ads_fb_init(struct platform_device *pdev)
 {
        u16 tmp;
@@ -227,7 +256,8 @@ static struct imxmmc_platform_data mx21ads_sdhc_pdata = {
        .exit = mx21ads_sdhc_exit,
 };
 
-static struct mxc_nand_platform_data mx21ads_nand_board_info = {
+static const struct mxc_nand_platform_data
+mx21ads_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
@@ -263,12 +293,12 @@ static void __init mx21ads_board_init(void)
        mxc_gpio_setup_multiple_pins(mx21ads_pins, ARRAY_SIZE(mx21ads_pins),
                        "mx21ads");
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device2, &uart_norts_pdata);
-       mxc_register_device(&mxc_uart_device3, &uart_pdata);
+       imx21_add_imx_uart0(&uart_pdata_rts);
+       imx21_add_imx_uart2(&uart_pdata_norts);
+       imx21_add_imx_uart3(&uart_pdata_rts);
        mxc_register_device(&mxc_fb_device, &mx21ads_fb_data);
        mxc_register_device(&mxc_sdhc_device0, &mx21ads_sdhc_pdata);
-       mxc_register_device(&imx21_nand_device, &mx21ads_nand_board_info);
+       imx21_add_mxc_nand(&mx21ads_nand_board_info);
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
similarity index 74%
rename from arch/arm/mach-mx2/mach-mx27_3ds.c
rename to arch/arm/mach-imx/mach-mx27_3ds.c
index b2f4e0db3fb3eeea439f25627bdc043dec6b5c76..e66ffaa1c26c26dbd4ba2b7d7b75c2455b06f5a1 100644 (file)
  * 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 machine is known as:
+ *  - i.MX27 3-Stack Development System
+ *  - i.MX27 Platform Development Kit (i.MX27 PDK)
  */
 
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/input/matrix_keypad.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx27.h>
-#include <mach/board-mx27pdk.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 static unsigned int mx27pdk_pins[] = {
@@ -58,7 +60,7 @@ static unsigned int mx27pdk_pins[] = {
        PF23_AIN_FEC_TX_EN,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -66,12 +68,34 @@ static struct platform_device *platform_devices[] __initdata = {
        &mxc_fec_device,
 };
 
+/*
+ * Matrix keyboard
+ */
+
+static const uint32_t mx27_3ds_keymap[] = {
+       KEY(0, 0, KEY_UP),
+       KEY(0, 1, KEY_DOWN),
+       KEY(1, 0, KEY_RIGHT),
+       KEY(1, 1, KEY_LEFT),
+       KEY(1, 2, KEY_ENTER),
+       KEY(2, 0, KEY_F6),
+       KEY(2, 1, KEY_F8),
+       KEY(2, 2, KEY_F9),
+       KEY(2, 3, KEY_F10),
+};
+
+static struct matrix_keymap_data mx27_3ds_keymap_data = {
+       .keymap         = mx27_3ds_keymap,
+       .keymap_size    = ARRAY_SIZE(mx27_3ds_keymap),
+};
+
 static void __init mx27pdk_init(void)
 {
        mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
                "mx27pdk");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx27_add_imx_uart0(&uart_pdata);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+       mxc_register_device(&imx_kpp_device, &mx27_3ds_keymap_data);
 }
 
 static void __init mx27pdk_timer_init(void)
similarity index 82%
rename from arch/arm/mach-mx2/mach-mx27ads.c
rename to arch/arm/mach-imx/mach-mx27ads.c
index 6ce323669e58f3efea4f10951b7cff0a38355f07..9c77da98a10eec59060e016088a63516a343aff2 100644 (file)
  * 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 <asm/mach/time.h>
 #include <asm/mach/map.h>
 #include <mach/gpio.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx27.h>
-#include <mach/board-mx27ads.h>
 #include <mach/mxc_nand.h>
-#include <mach/i2c.h>
 #include <mach/imxfb.h>
 #include <mach/mmc.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
+/*
+ * Base address of PBC controller, CS4
+ */
+#define PBC_BASE_ADDRESS        0xf4300000
+#define PBC_REG_ADDR(offset)    (void __force __iomem *) \
+               (PBC_BASE_ADDRESS + (offset))
+
+/* When the PBC address connection is fixed in h/w, defined as 1 */
+#define PBC_ADDR_SH             0
+
+/* Offsets for the PBC Controller register */
+/*
+ * PBC Board version register offset
+ */
+#define PBC_VERSION_REG         PBC_REG_ADDR(0x00000 >> PBC_ADDR_SH)
+/*
+ * PBC Board control register 1 set address.
+ */
+#define PBC_BCTRL1_SET_REG      PBC_REG_ADDR(0x00008 >> PBC_ADDR_SH)
+/*
+ * PBC Board control register 1 clear address.
+ */
+#define PBC_BCTRL1_CLEAR_REG    PBC_REG_ADDR(0x0000C >> PBC_ADDR_SH)
+
+/* PBC Board Control Register 1 bit definitions */
+#define PBC_BCTRL1_LCDON        0x0800 /* Enable the LCD */
+
+/* to determine the correct external crystal reference */
+#define CKIH_27MHZ_BIT_SET      (1 << 3)
+
 static unsigned int mx27ads_pins[] = {
        /* UART0 */
        PE12_PF_UART1_TXD,
@@ -141,7 +165,8 @@ static unsigned int mx27ads_pins[] = {
        PB9_PF_SD2_CLK,
 };
 
-static struct mxc_nand_platform_data mx27ads_nand_board_info = {
+static const struct mxc_nand_platform_data
+mx27ads_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
@@ -168,7 +193,7 @@ static struct platform_device mx27ads_nor_mtd_device = {
        .resource = &mx27ads_flash_resource,
 };
 
-static struct imxi2c_platform_data mx27ads_i2c_data = {
+static const struct imxi2c_platform_data mx27ads_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -263,20 +288,8 @@ static struct platform_device *platform_devices[] __initdata = {
        &mxc_w1_master_device,
 };
 
-static struct imxuart_platform_data uart_pdata[] = {
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       },
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
 };
 
 static void __init mx27ads_board_init(void)
@@ -284,18 +297,18 @@ static void __init mx27ads_board_init(void)
        mxc_gpio_setup_multiple_pins(mx27ads_pins, ARRAY_SIZE(mx27ads_pins),
                        "mx27ads");
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
-       mxc_register_device(&mxc_uart_device3, &uart_pdata[3]);
-       mxc_register_device(&mxc_uart_device4, &uart_pdata[4]);
-       mxc_register_device(&mxc_uart_device5, &uart_pdata[5]);
-       mxc_register_device(&imx27_nand_device, &mx27ads_nand_board_info);
+       imx27_add_imx_uart0(&uart_pdata);
+       imx27_add_imx_uart1(&uart_pdata);
+       imx27_add_imx_uart2(&uart_pdata);
+       imx27_add_imx_uart3(&uart_pdata);
+       imx27_add_imx_uart4(&uart_pdata);
+       imx27_add_imx_uart5(&uart_pdata);
+       imx27_add_mxc_nand(&mx27ads_nand_board_info);
 
        /* only the i2c master 1 is used on this CPU card */
        i2c_register_board_info(1, mx27ads_i2c_devices,
                                ARRAY_SIZE(mx27ads_i2c_devices));
-       mxc_register_device(&mxc_i2c_device1, &mx27ads_i2c_data);
+       imx27_add_i2c_imx1(&mx27ads_i2c1_data);
        mxc_register_device(&mxc_fb_device, &mx27ads_fb_data);
        mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
        mxc_register_device(&mxc_sdhc_device1, &sdhc2_pdata);
@@ -342,4 +355,3 @@ MACHINE_START(MX27ADS, "Freescale i.MX27ADS")
        .init_machine   = mx27ads_board_init,
        .timer          = &mx27ads_timer,
 MACHINE_END
-
similarity index 86%
rename from arch/arm/mach-mx2/mach-mxt_td60.c
rename to arch/arm/mach-imx/mach-mxt_td60.c
index bc3855992677d34a4cd6ed9064c089d85e568022..a3a1e452d4c5a15bef12ced37d70d275fabd2fad 100644 (file)
  * 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 <asm/mach/time.h>
 #include <asm/mach/map.h>
 #include <linux/gpio.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx27.h>
 #include <mach/mxc_nand.h>
-#include <mach/i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <mach/imxfb.h>
 #include <mach/mmc.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 static unsigned int mxt_td60_pins[] __initdata = {
@@ -128,12 +123,13 @@ static unsigned int mxt_td60_pins[] __initdata = {
        PB9_PF_SD2_CLK,
 };
 
-static struct mxc_nand_platform_data mxt_td60_nand_board_info = {
+static const struct mxc_nand_platform_data
+mxt_td60_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
 
-static struct imxi2c_platform_data mxt_td60_i2c_data = {
+static const struct imxi2c_platform_data mxt_td60_i2c0_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -173,7 +169,7 @@ static struct i2c_board_info mxt_td60_i2c_devices[] = {
        },
 };
 
-static struct imxi2c_platform_data mxt_td60_i2c2_data = {
+static const struct imxi2c_platform_data mxt_td60_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -239,14 +235,8 @@ static struct platform_device *platform_devices[] __initdata = {
        &mxc_fec_device,
 };
 
-static struct imxuart_platform_data uart_pdata[] = {
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       },
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
 };
 
 static void __init mxt_td60_board_init(void)
@@ -254,10 +244,10 @@ static void __init mxt_td60_board_init(void)
        mxc_gpio_setup_multiple_pins(mxt_td60_pins, ARRAY_SIZE(mxt_td60_pins),
                        "MXT_TD60");
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
-       mxc_register_device(&imx27_nand_device, &mxt_td60_nand_board_info);
+       imx27_add_imx_uart0(&uart_pdata);
+       imx27_add_imx_uart1(&uart_pdata);
+       imx27_add_imx_uart2(&uart_pdata);
+       imx27_add_mxc_nand(&mxt_td60_nand_board_info);
 
        i2c_register_board_info(0, mxt_td60_i2c_devices,
                                ARRAY_SIZE(mxt_td60_i2c_devices));
@@ -265,8 +255,8 @@ static void __init mxt_td60_board_init(void)
        i2c_register_board_info(1, mxt_td60_i2c2_devices,
                                ARRAY_SIZE(mxt_td60_i2c2_devices));
 
-       mxc_register_device(&mxc_i2c_device0, &mxt_td60_i2c_data);
-       mxc_register_device(&mxc_i2c_device1, &mxt_td60_i2c2_data);
+       imx27_add_i2c_imx0(&mxt_td60_i2c0_data);
+       imx27_add_i2c_imx1(&mxt_td60_i2c1_data);
        mxc_register_device(&mxc_fb_device, &mxt_td60_fb_data);
        mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
 
similarity index 80%
rename from arch/arm/mach-mx2/mach-pca100.c
rename to arch/arm/mach-imx/mach-pca100.c
index a87422ed4ff5a1ea9bd4f07605092bc646842ca9..6c92deaf468f6677559655fe366fba8aad97006c 100644 (file)
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/iomux-mx27.h>
-#include <mach/i2c.h>
 #include <asm/mach/time.h>
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
-#include <mach/spi.h>
-#endif
-#include <mach/imx-uart.h>
 #include <mach/audmux.h>
 #include <mach/ssi.h>
 #include <mach/mxc_nand.h>
 #include <mach/mmc.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
+#include <mach/imxfb.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 #define OTG_PHY_CS_GPIO (GPIO_PORTB + 23)
 #define USBH2_PHY_CS_GPIO (GPIO_PORTB + 24)
+#define SPI1_SS0 (GPIO_PORTD + 28)
+#define SPI1_SS1 (GPIO_PORTD + 27)
+#define SD2_CD (GPIO_PORTC + 29)
 
 static int pca100_pins[] = {
        /* UART1 */
@@ -68,6 +68,7 @@ static int pca100_pins[] = {
        PB7_PF_SD2_D3,
        PB8_PF_SD2_CMD,
        PB9_PF_SD2_CLK,
+       SD2_CD | GPIO_GPIO | GPIO_IN,
        /* FEC */
        PD0_AIN_FEC_TXD0,
        PD1_AIN_FEC_TXD1,
@@ -131,13 +132,42 @@ static int pca100_pins[] = {
        PD23_AF_USBH2_DATA2,
        PD24_AF_USBH2_DATA1,
        PD26_AF_USBH2_DATA5,
+       /* display */
+       PA5_PF_LSCLK,
+       PA6_PF_LD0,
+       PA7_PF_LD1,
+       PA8_PF_LD2,
+       PA9_PF_LD3,
+       PA10_PF_LD4,
+       PA11_PF_LD5,
+       PA12_PF_LD6,
+       PA13_PF_LD7,
+       PA14_PF_LD8,
+       PA15_PF_LD9,
+       PA16_PF_LD10,
+       PA17_PF_LD11,
+       PA18_PF_LD12,
+       PA19_PF_LD13,
+       PA20_PF_LD14,
+       PA21_PF_LD15,
+       PA22_PF_LD16,
+       PA23_PF_LD17,
+       PA26_PF_PS,
+       PA28_PF_HSYNC,
+       PA29_PF_VSYNC,
+       PA31_PF_OE_ACD,
+       /* free GPIO */
+       GPIO_PORTC | 31 | GPIO_GPIO | GPIO_IN, /* GPIO0_IRQ */
+       GPIO_PORTC | 25 | GPIO_GPIO | GPIO_IN, /* GPIO1_IRQ */
+       GPIO_PORTE | 5 | GPIO_GPIO | GPIO_IN, /* GPIO2_IRQ */
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct mxc_nand_platform_data pca100_nand_board_info = {
+static const struct mxc_nand_platform_data
+pca100_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
@@ -148,7 +178,7 @@ static struct platform_device *platform_devices[] __initdata = {
        &mxc_wdt,
 };
 
-static struct imxi2c_platform_data pca100_i2c_1_data = {
+static const struct imxi2c_platform_data pca100_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -189,9 +219,9 @@ static struct spi_board_info pca100_spi_board_info[] __initdata = {
        },
 };
 
-static int pca100_spi_cs[] = {GPIO_PORTD + 28, GPIO_PORTD + 27};
+static int pca100_spi_cs[] = {SPI1_SS0, SPI1_SS1};
 
-static struct spi_imx_master pca100_spi_0_data = {
+static const struct spi_imx_master pca100_spi0_data __initconst = {
        .chipselect     = pca100_spi_cs,
        .num_chipselect = ARRAY_SIZE(pca100_spi_cs),
 };
@@ -253,6 +283,7 @@ static struct imxmmc_platform_data sdhc_pdata = {
        .exit = pca100_sdhc2_exit,
 };
 
+#if defined(CONFIG_USB_ULPI)
 static int otg_phy_init(struct platform_device *pdev)
 {
        gpio_set_value(OTG_PHY_CS_GPIO, 0);
@@ -276,6 +307,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
        .portsc = MXC_EHCI_MODE_ULPI,
        .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
 };
+#endif
 
 static struct fsl_usb2_platform_data otg_device_pdata = {
        .operating_mode = FSL_USB2_DR_DEVICE,
@@ -297,6 +329,45 @@ static int __init pca100_otg_mode(char *options)
 }
 __setup("otg_mode=", pca100_otg_mode);
 
+/* framebuffer info */
+static struct imx_fb_videomode pca100_fb_modes[] = {
+       {
+               .mode = {
+                       .name           = "EMERGING-ETV570G0DHU",
+                       .refresh        = 60,
+                       .xres           = 640,
+                       .yres           = 480,
+                       .pixclock       = 39722, /* in ps (25.175 MHz) */
+                       .hsync_len      = 30,
+                       .left_margin    = 114,
+                       .right_margin   = 16,
+                       .vsync_len      = 3,
+                       .upper_margin   = 32,
+                       .lower_margin   = 0,
+               },
+               /*
+                * TFT
+                * Pixel pol active high
+                * HSYNC active low
+                * VSYNC active low
+                * use HSYNC for ACD count
+                * line clock disable while idle
+                * always enable line clock even if no data
+                */
+               .pcr = 0xf0c08080,
+               .bpp = 16,
+       },
+};
+
+static struct imx_fb_platform_data pca100_fb_data = {
+       .mode = pca100_fb_modes,
+       .num_modes = ARRAY_SIZE(pca100_fb_modes),
+
+       .pwmr           = 0x00A903FF,
+       .lscr1          = 0x00120300,
+       .dmacr          = 0x00020010,
+};
+
 static void __init pca100_init(void)
 {
        int ret;
@@ -320,33 +391,24 @@ static void __init pca100_init(void)
 
        mxc_register_device(&imx_ssi_device0, &pca100_ssi_pdata);
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx27_add_imx_uart0(&uart_pdata);
 
-       mxc_gpio_mode(GPIO_PORTC | 29 | GPIO_GPIO | GPIO_IN);
        mxc_register_device(&mxc_sdhc_device1, &sdhc_pdata);
 
-       mxc_register_device(&imx27_nand_device, &pca100_nand_board_info);
+       imx27_add_mxc_nand(&pca100_nand_board_info);
 
        /* only the i2c master 1 is used on this CPU card */
        i2c_register_board_info(1, pca100_i2c_devices,
                                ARRAY_SIZE(pca100_i2c_devices));
 
-       mxc_register_device(&mxc_i2c_device1, &pca100_i2c_1_data);
-
-       mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
-       mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_OUT);
-
-       /* GPIO0_IRQ */
-       mxc_gpio_mode(GPIO_PORTC | 31 | GPIO_GPIO | GPIO_IN);
-       /* GPIO1_IRQ */
-       mxc_gpio_mode(GPIO_PORTC | 25 | GPIO_GPIO | GPIO_IN);
-       /* GPIO2_IRQ */
-       mxc_gpio_mode(GPIO_PORTE | 5 | GPIO_GPIO | GPIO_IN);
+       imx27_add_i2c_imx1(&pca100_i2c1_data);
 
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
+       mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_IN);
+       mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN);
        spi_register_board_info(pca100_spi_board_info,
                                ARRAY_SIZE(pca100_spi_board_info));
-       mxc_register_device(&mxc_spi_device0, &pca100_spi_0_data);
+       imx27_add_spi_imx0(&pca100_spi_0_data);
 #endif
 
        gpio_request(OTG_PHY_CS_GPIO, "usb-otg-cs");
@@ -372,6 +434,8 @@ static void __init pca100_init(void)
                mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
        }
 
+       mxc_register_device(&mxc_fb_device, &pca100_fb_data);
+
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
 
similarity index 91%
rename from arch/arm/mach-mx2/mach-pcm038.c
rename to arch/arm/mach-imx/mach-pcm038.c
index 36c89431679a93edd5e66118ce9eb9b5838b9045..9212e8f37001d050418b505bdb7c8874b94cd9f0 100644 (file)
 #include <mach/board-pcm038.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/i2c.h>
 #include <mach/iomux-mx27.h>
-#include <mach/imx-uart.h>
 #include <mach/mxc_nand.h>
-#include <mach/spi.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx27.h"
 #include "devices.h"
 
 static int pcm038_pins[] = {
@@ -162,17 +160,12 @@ static struct platform_device pcm038_nor_mtd_device = {
        .resource = &pcm038_flash_resource,
 };
 
-static struct imxuart_platform_data uart_pdata[] = {
-       {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       }, {
-               .flags = IMXUART_HAVE_RTSCTS,
-       },
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct mxc_nand_platform_data pcm038_nand_board_info = {
+static const struct mxc_nand_platform_data
+pcm038_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
@@ -192,7 +185,7 @@ static void __init pcm038_init_sram(void)
        mx27_setup_weimcs(1, 0x0000d843, 0x22252521, 0x22220a00);
 }
 
-static struct imxi2c_platform_data pcm038_i2c_1_data = {
+static const struct imxi2c_platform_data pcm038_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -215,7 +208,7 @@ static struct i2c_board_info pcm038_i2c_devices[] = {
 
 static int pcm038_spi_cs[] = {GPIO_PORTD + 28};
 
-static struct spi_imx_master pcm038_spi_0_data = {
+static const struct spi_imx_master pcm038_spi0_data __initconst = {
        .chipselect = pcm038_spi_cs,
        .num_chipselect = ARRAY_SIZE(pcm038_spi_cs),
 };
@@ -305,18 +298,18 @@ static void __init pcm038_init(void)
 
        pcm038_init_sram();
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
+       imx27_add_imx_uart0(&uart_pdata);
+       imx27_add_imx_uart1(&uart_pdata);
+       imx27_add_imx_uart2(&uart_pdata);
 
        mxc_gpio_mode(PE16_AF_OWIRE);
-       mxc_register_device(&imx27_nand_device, &pcm038_nand_board_info);
+       imx27_add_mxc_nand(&pcm038_nand_board_info);
 
        /* only the i2c master 1 is used on this CPU card */
        i2c_register_board_info(1, pcm038_i2c_devices,
                                ARRAY_SIZE(pcm038_i2c_devices));
 
-       mxc_register_device(&mxc_i2c_device1, &pcm038_i2c_1_data);
+       imx27_add_i2c_imx1(&pcm038_i2c1_data);
 
        /* PE18 for user-LED D40 */
        mxc_gpio_mode(GPIO_PORTE | 18 | GPIO_GPIO | GPIO_OUT);
@@ -326,7 +319,7 @@ static void __init pcm038_init(void)
        /* MC13783 IRQ */
        mxc_gpio_mode(GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN);
 
-       mxc_register_device(&mxc_spi_device0, &pcm038_spi_0_data);
+       imx27_add_spi_imx0(&pcm038_spi0_data);
        spi_register_board_info(pcm038_spi_board_info,
                                ARRAY_SIZE(pcm038_spi_board_info));
 
similarity index 89%
rename from arch/arm/mach-mx1/mach-scb9328.c
rename to arch/arm/mach-imx/mach-scb9328.c
index 7587a7a12460242d9f4b25b2233efef6dc5bab65..88bf0d1e26e6ebb3400e07db4f545e3f86c97b9b 100644 (file)
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx1.h>
 
+#include "devices-imx1.h"
 #include "devices.h"
 
 /*
  * This scb9328 has a 32MiB flash
  */
 static struct resource flash_resource = {
-       .start  = IMX_CS0_PHYS,
-       .end    = IMX_CS0_PHYS + (32 * 1024 * 1024) - 1,
+       .start  = MX1_CS0_PHYS,
+       .end    = MX1_CS0_PHYS + (32 * 1024 * 1024) - 1,
        .flags  = IORESOURCE_MEM,
 };
 
@@ -70,13 +70,13 @@ static struct dm9000_plat_data dm9000_platdata = {
 static struct resource dm9000x_resources[] = {
        {
                .name   = "address area",
-               .start  = IMX_CS5_PHYS,
-               .end    = IMX_CS5_PHYS + 1,
+               .start  = MX1_CS5_PHYS,
+               .end    = MX1_CS5_PHYS + 1,
                .flags  = IORESOURCE_MEM,       /* address access */
        }, {
                .name   = "data area",
-               .start  = IMX_CS5_PHYS + 4,
-               .end    = IMX_CS5_PHYS + 5,
+               .start  = MX1_CS5_PHYS + 4,
+               .end    = MX1_CS5_PHYS + 5,
                .flags  = IORESOURCE_MEM,       /* data access */
        }, {
                .start  = IRQ_GPIOC(3),
@@ -108,14 +108,13 @@ static int uart1_mxc_init(struct platform_device *pdev)
                        ARRAY_SIZE(mxc_uart1_pins), "UART1");
 }
 
-static int uart1_mxc_exit(struct platform_device *pdev)
+static void uart1_mxc_exit(struct platform_device *pdev)
 {
        mxc_gpio_release_multiple_pins(mxc_uart1_pins,
                        ARRAY_SIZE(mxc_uart1_pins));
-       return 0;
 }
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .init = uart1_mxc_init,
        .exit = uart1_mxc_exit,
        .flags = IMXUART_HAVE_RTSCTS,
@@ -131,7 +130,7 @@ static struct platform_device *devices[] __initdata = {
  */
 static void __init scb9328_init(void)
 {
-       mxc_register_device(&imx_uart1_device, &uart_pdata);
+       imx1_add_imx_uart0(&uart_pdata);
 
        printk(KERN_INFO"Scb9328: Adding devices\n");
        platform_add_devices(devices, ARRAY_SIZE(devices));
similarity index 68%
rename from arch/arm/mach-mx1/generic.c
rename to arch/arm/mach-imx/mm-imx1.c
index 7f9fc1034c0884b186e2ccb7ec6bc5348598d50a..9be92b96dc8961d02efe8a019ac95a46d1647295 100644 (file)
@@ -3,7 +3,7 @@
  *  Created: april 20th, 2004
  *  Copyright: Synertronixx GmbH
  *
- *  Common code for i.MX machines
+ *  Common code for i.MX1 machines
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 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/init.h>
 
 static struct map_desc imx_io_desc[] __initdata = {
        {
-               .virtual        = IMX_IO_BASE,
-               .pfn            = __phys_to_pfn(IMX_IO_PHYS),
-               .length         = IMX_IO_SIZE,
-               .type           = MT_DEVICE
+               .virtual = MX1_IO_BASE_ADDR_VIRT,
+               .pfn = __phys_to_pfn(MX1_IO_BASE_ADDR),
+               .length = MX1_IO_SIZE,
+               .type = MT_DEVICE
        }
 };
 
 void __init mx1_map_io(void)
 {
        mxc_set_cpu_type(MXC_CPU_MX1);
-       mxc_arch_reset_init(IO_ADDRESS(WDT_BASE_ADDR));
+       mxc_arch_reset_init(MX1_IO_ADDRESS(MX1_WDT_BASE_ADDR));
 
        iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
 }
 
+int imx1_register_gpios(void);
+
 void __init mx1_init_irq(void)
 {
-       mxc_init_irq(IO_ADDRESS(AVIC_BASE_ADDR));
+       mxc_init_irq(MX1_IO_ADDRESS(MX1_AVIC_BASE_ADDR));
+       imx1_register_gpios();
 }
-
similarity index 95%
rename from arch/arm/mach-mx2/mm-imx21.c
rename to arch/arm/mach-imx/mm-imx21.c
index 64134314d012a43b43f80d2690abaad92f5cee0b..12faeeaa0a9706ce4ea2eb0c774abff437dc9901 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-mx2/mm-imx21.c
+ * arch/arm/mach-imx/mm-imx21.c
  *
  * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
  *
@@ -77,7 +77,10 @@ void __init mx21_map_io(void)
        iotable_init(imx21_io_desc, ARRAY_SIZE(imx21_io_desc));
 }
 
+int imx21_register_gpios(void);
+
 void __init mx21_init_irq(void)
 {
        mxc_init_irq(MX21_IO_ADDRESS(MX21_AVIC_BASE_ADDR));
+       imx21_register_gpios();
 }
similarity index 95%
rename from arch/arm/mach-mx2/mm-imx27.c
rename to arch/arm/mach-imx/mm-imx27.c
index 3366ed44cfd5a60b283d2266bd083ffe664047e0..a24622957ff2dc3eeed0f1e949d4a12fc35a9e30 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-mx2/mm-imx27.c
+ * arch/arm/mach-imx/mm-imx27.c
  *
  * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
  *
@@ -77,7 +77,10 @@ void __init mx27_map_io(void)
        iotable_init(imx27_io_desc, ARRAY_SIZE(imx27_io_desc));
 }
 
+int imx27_register_gpios(void);
+
 void __init mx27_init_irq(void)
 {
        mxc_init_irq(MX27_IO_ADDRESS(MX27_AVIC_BASE_ADDR));
+       imx27_register_gpios();
 }
diff --git a/arch/arm/mach-imx/pm-imx27.c b/arch/arm/mach-imx/pm-imx27.c
new file mode 100644 (file)
index 0000000..afc17ce
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * i.MX27 Power Management Routines
+ *
+ * Based on Freescale's BSP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/io.h>
+#include <mach/system.h>
+#include <mach/mx27.h>
+
+static int mx27_suspend_enter(suspend_state_t state)
+{
+       u32 cscr;
+       switch (state) {
+       case PM_SUSPEND_MEM:
+               /* Clear MPEN and SPEN to disable MPLL/SPLL */
+               cscr = __raw_readl(MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR));
+               cscr &= 0xFFFFFFFC;
+               __raw_writel(cscr, MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR));
+               /* Executes WFI */
+               arch_idle();
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static struct platform_suspend_ops mx27_suspend_ops = {
+       .enter = mx27_suspend_enter,
+       .valid = suspend_valid_only_mem,
+};
+
+static int __init mx27_pm_init(void)
+{
+       suspend_set_ops(&mx27_suspend_ops);
+       return 0;
+}
+
+device_initcall(mx27_pm_init);
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
new file mode 100644 (file)
index 0000000..5f96e15
--- /dev/null
@@ -0,0 +1 @@
+void integrator_reserve(void);
index b02cfc06e0aeeff452a2c3813523fccd53f1edf2..8f4fb6d638f7ea66717a5afb5d962ef0d88723a3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/memblock.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/termios.h>
@@ -30,6 +31,7 @@
 #include <asm/system.h>
 #include <asm/leds.h>
 #include <asm/mach/time.h>
+#include <asm/pgtable.h>
 
 static struct amba_pl010_data integrator_uart_data;
 
@@ -119,8 +121,13 @@ static struct clk uartclk = {
        .rate   = 14745600,
 };
 
+static struct clk dummy_apb_pclk;
+
 static struct clk_lookup lookups[] = {
-       {       /* UART0 */
+       {       /* Bus clock */
+               .con_id         = "apb_pclk",
+               .clk            = &dummy_apb_pclk,
+       }, {    /* UART0 */
                .dev_id         = "mb:16",
                .clk            = &uartclk,
        }, {    /* UART1 */
@@ -215,3 +222,13 @@ void cm_control(u32 mask, u32 set)
 }
 
 EXPORT_SYMBOL(cm_control);
+
+/*
+ * We need to stop things allocating the low memory; ideally we need a
+ * better implementation of GFP_DMA which does not assume that DMA-able
+ * memory starts at zero.
+ */
+void __init integrator_reserve(void)
+{
+       memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
+}
index 227cf4d05088ec85bf870e1423b7044d0758d133..6ab5a03ab9d8b0a7f45311595b0ee1fa16474ef3 100644 (file)
@@ -48,6 +48,8 @@
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
+#include "common.h"
+
 /* 
  * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
  * is the (PA >> 12).
@@ -502,6 +504,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator")
        .io_pg_offst    = ((0xf1600000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ap_map_io,
+       .reserve        = integrator_reserve,
        .init_irq       = ap_init_irq,
        .timer          = &ap_timer,
        .init_machine   = ap_init,
index cde57b2b83b57a36288382ef5b57a39ae895d802..05db40e3c4f75a7fcf661718269cdcf330d7f9cc 100644 (file)
@@ -43,6 +43,8 @@
 
 #include <plat/timer-sp.h>
 
+#include "common.h"
+
 #define INTCP_PA_FLASH_BASE            0x24000000
 #define INTCP_FLASH_SIZE               SZ_32M
 
@@ -601,6 +603,7 @@ MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
        .io_pg_offst    = ((0xf1600000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = intcp_map_io,
+       .reserve        = integrator_reserve,
        .init_irq       = intcp_init_irq,
        .timer          = &cp_timer,
        .init_machine   = intcp_init,
index 9cef0590d5aa3d4af92e62d41601b7057f94e0b3..6467d99fa2ee4a0c674d9071dad669cb5caa7b32 100644 (file)
@@ -505,10 +505,10 @@ void __init pci_v3_preinit(void)
        /*
         * Hook in our fault handler for PCI errors
         */
-       hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch");
-       hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch");
-       hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
-       hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
+       hook_fault_code(4, v3_pci_fault, SIGBUS, 0, "external abort on linefetch");
+       hook_fault_code(6, v3_pci_fault, SIGBUS, 0, "external abort on linefetch");
+       hook_fault_code(8, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch");
+       hook_fault_code(10, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch");
 
        spin_lock_irqsave(&v3_lock, flags);
 
index 25b1da9a5035469fcf4355e80082f3dd7af586c8..7415e4338651e7c84e2e3a587092a1c1859cda1d 100644 (file)
@@ -69,6 +69,4 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
 #endif /* CONFIG_ARCH_IOP13XX */
 #endif /* !ASSEMBLY */
 
-#define PFN_TO_NID(addr)       (0)
-
 #endif
index 6d5a90813d31b6b96532b3b1a5cdb555e972ec41..773ea0c95b9f6fc91d8c9c57f3a3bd0f714b306d 100644 (file)
@@ -987,7 +987,7 @@ void __init iop13xx_pci_init(void)
                iop13xx_atux_setup();
        }
 
-       hook_fault_code(16+6, iop13xx_pci_abort, SIGBUS,
+       hook_fault_code(16+6, iop13xx_pci_abort, SIGBUS, 0,
                        "imprecise external abort");
 }
 
index 90771cad06f86f7fe3238021ce8ae39ce90cadc2..f797c5f538b094e2d600c78b85d70d70ff25d295 100644 (file)
@@ -209,7 +209,7 @@ ixp2000_pci_preinit(void)
                        "the needed workaround has not been configured in");
 #endif
 
-       hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
+       hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, 0,
                                "PCI config cycle to non-existent device");
 }
 
index 4b0e598a91c91f4573d927a8016d91aab0154f7d..563819a83292db81f72b147986b98b573868149f 100644 (file)
@@ -229,7 +229,7 @@ void __init ixp23xx_pci_preinit(void)
 {
        ixp23xx_pci_common_init();
 
-       hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS,
+       hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, 0,
                        "PCI config cycle to non-existent device");
 
        *IXP23XX_PCI_ADDR_EXT = 0x0000e000;
index e3181534c7f9dba7fe1cc8f6e4185aae21c8c87b..61cd4d64b98596c7507dcaf67d069dbe22508e50 100644 (file)
@@ -348,7 +348,7 @@ int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
  * This is really ugly and we need a better way of specifying
  * DMA-capable regions of memory.
  */
-void __init ixp4xx_adjust_zones(int node, unsigned long *zone_size,
+void __init ixp4xx_adjust_zones(unsigned long *zone_size,
        unsigned long *zhole_size)
 {
        unsigned int sz = SZ_64M >> PAGE_SHIFT;
@@ -356,7 +356,7 @@ void __init ixp4xx_adjust_zones(int node, unsigned long *zone_size,
        /*
         * Only adjust if > 64M on current system
         */
-       if (node || (zone_size[0] <= sz))
+       if (zone_size[0] <= sz)
                return;
 
        zone_size[1] = zone_size[0] - sz;
@@ -382,7 +382,8 @@ void __init ixp4xx_pci_preinit(void)
 
 
        /* hook in our fault handler for PCI errors */
-       hook_fault_code(16+6, abort_handler, SIGBUS, "imprecise external abort");
+       hook_fault_code(16+6, abort_handler, SIGBUS, 0,
+                       "imprecise external abort");
 
        pr_debug("setup PCI-AHB(inbound) and AHB-PCI(outbound) address mappings\n");
 
index 98f5e5e2098001398d45930d2fb5d33b3452f0ea..0136eaa29224a538cfdd65179dd59432fa7b1488 100644 (file)
 
 #if !defined(__ASSEMBLY__) && defined(CONFIG_PCI)
 
-void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes);
+void ixp4xx_adjust_zones(unsigned long *size, unsigned long *holes);
 
-#define arch_adjust_zones(node, size, holes) \
-       ixp4xx_adjust_zones(node, size, holes)
+#define arch_adjust_zones(size, holes) \
+       ixp4xx_adjust_zones(size, holes)
 
 #define ISA_DMA_THRESHOLD (SZ_64M - 1)
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_64M)
index 29b2163b1fe3b3cff4ce40e9c23b112c360e1a56..cc25501b57fa8edf270752e0a719f2564965f44a 100644 (file)
@@ -75,6 +75,13 @@ config MACH_OPENRD_CLIENT
          Say 'Y' here if you want your kernel to support the
          Marvell OpenRD Client Board.
 
+config MACH_OPENRD_ULTIMATE
+       bool "Marvell OpenRD Ultimate Board"
+       select MACH_OPENRD
+       help
+         Say 'Y' here if you want your kernel to support the
+         Marvell OpenRD Ultimate Board.
+
 config MACH_NETSPACE_V2
        bool "LaCie Network Space v2 NAS Board"
        help
@@ -87,6 +94,12 @@ config MACH_INETSPACE_V2
          Say 'Y' here if you want your kernel to support the
          LaCie Internet Space v2 NAS.
 
+config MACH_NETSPACE_MAX_V2
+       bool "LaCie Network Space Max v2 NAS Board"
+       help
+         Say 'Y' here if you want your kernel to support the
+         LaCie Network Space Max v2 NAS.
+
 config MACH_NET2BIG_V2
        bool "LaCie 2Big Network v2 NAS Board"
        help
@@ -99,6 +112,12 @@ config MACH_NET5BIG_V2
          Say 'Y' here if you want your kernel to support the
          LaCie 5Big Network v2 NAS.
 
+config MACH_T5325
+       bool "HP t5325 Thin Client"
+       help
+         Say 'Y' here if you want your kernel to support the
+         HP t5325 Thin Client.
+
 endmenu
 
 endif
index c0cd5d362002c325cee09cc8a8c8a59cfaaebf26..295d7baa6ae11150956e004330259859ef3c4ec6 100644 (file)
@@ -12,7 +12,9 @@ obj-$(CONFIG_MACH_TS41X)              += ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_OPENRD)              += openrd-setup.o
 obj-$(CONFIG_MACH_NETSPACE_V2)         += netspace_v2-setup.o
 obj-$(CONFIG_MACH_INETSPACE_V2)                += netspace_v2-setup.o
+obj-$(CONFIG_MACH_NETSPACE_MAX_V2)     += netspace_v2-setup.o
 obj-$(CONFIG_MACH_NET2BIG_V2)          += netxbig_v2-setup.o
 obj-$(CONFIG_MACH_NET5BIG_V2)          += netxbig_v2-setup.o
+obj-$(CONFIG_MACH_T5325)               += t5325-setup.o
 
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
index 2e69168fc699881d9928964c266eb7c866c00ee2..8d03bcef5182c8a9696159c8c220da833ee2cbd6 100644 (file)
@@ -31,6 +31,8 @@
 #define ATTR_DEV_CS0           0x3e
 #define ATTR_PCIE_IO           0xe0
 #define ATTR_PCIE_MEM          0xe8
+#define ATTR_PCIE1_IO          0xd0
+#define ATTR_PCIE1_MEM         0xd8
 #define ATTR_SRAM              0x01
 
 /*
@@ -106,17 +108,21 @@ void __init kirkwood_setup_cpu_mbus(void)
                      TARGET_PCIE, ATTR_PCIE_IO, KIRKWOOD_PCIE_IO_BUS_BASE);
        setup_cpu_win(1, KIRKWOOD_PCIE_MEM_PHYS_BASE, KIRKWOOD_PCIE_MEM_SIZE,
                      TARGET_PCIE, ATTR_PCIE_MEM, KIRKWOOD_PCIE_MEM_BUS_BASE);
+       setup_cpu_win(2, KIRKWOOD_PCIE1_IO_PHYS_BASE, KIRKWOOD_PCIE1_IO_SIZE,
+                     TARGET_PCIE, ATTR_PCIE1_IO, KIRKWOOD_PCIE1_IO_BUS_BASE);
+       setup_cpu_win(3, KIRKWOOD_PCIE1_MEM_PHYS_BASE, KIRKWOOD_PCIE1_MEM_SIZE,
+                     TARGET_PCIE, ATTR_PCIE1_MEM, KIRKWOOD_PCIE1_MEM_BUS_BASE);
 
        /*
         * Setup window for NAND controller.
         */
-       setup_cpu_win(2, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
+       setup_cpu_win(4, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
                      TARGET_DEV_BUS, ATTR_DEV_NAND, -1);
 
        /*
         * Setup window for SRAM.
         */
-       setup_cpu_win(3, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE,
+       setup_cpu_win(5, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE,
                      TARGET_SRAM, ATTR_SRAM, -1);
 
        /*
index 6072eaa5e66acf81f080d72374fbfd1dfbe7382c..9dd67c7b44590dafa63dcb11204998fe8c3d3ad3 100644 (file)
@@ -43,6 +43,11 @@ static struct map_desc kirkwood_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(KIRKWOOD_PCIE_IO_PHYS_BASE),
                .length         = KIRKWOOD_PCIE_IO_SIZE,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = KIRKWOOD_PCIE1_IO_VIRT_BASE,
+               .pfn            = __phys_to_pfn(KIRKWOOD_PCIE1_IO_PHYS_BASE),
+               .length         = KIRKWOOD_PCIE1_IO_SIZE,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = KIRKWOOD_REGS_VIRT_BASE,
                .pfn            = __phys_to_pfn(KIRKWOOD_REGS_PHYS_BASE),
@@ -402,7 +407,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data)
        u32 dev, rev;
 
        kirkwood_pcie_id(&dev, &rev);
-       if (rev == 0 /* catch all Kirkwood Z0's */
+       if (rev == 0 && dev != MV88F6282_DEV_ID) /* catch all Kirkwood Z0's */
                mvsdio_data->clock = 100000000;
        else
                mvsdio_data->clock = 200000000;
@@ -847,8 +852,10 @@ int __init kirkwood_find_tclk(void)
        u32 dev, rev;
 
        kirkwood_pcie_id(&dev, &rev);
-       if (dev == MV88F6281_DEV_ID && (rev == MV88F6281_REV_A0 ||
-                                       rev == MV88F6281_REV_A1))
+
+       if ((dev == MV88F6281_DEV_ID && (rev == MV88F6281_REV_A0 ||
+                                       rev == MV88F6281_REV_A1)) ||
+           (dev == MV88F6282_DEV_ID))
                return 200000000;
 
        return 166666667;
@@ -891,13 +898,22 @@ static char * __init kirkwood_id(void)
                        return "MV88F6192-Z0";
                else if (rev == MV88F6192_REV_A0)
                        return "MV88F6192-A0";
+               else if (rev == MV88F6192_REV_A1)
+                       return "MV88F6192-A1";
                else
                        return "MV88F6192-Rev-Unsupported";
        } else if (dev == MV88F6180_DEV_ID) {
                if (rev == MV88F6180_REV_A0)
                        return "MV88F6180-Rev-A0";
+               else if (rev == MV88F6180_REV_A1)
+                       return "MV88F6180-Rev-A1";
                else
                        return "MV88F6180-Rev-Unsupported";
+       } else if (dev == MV88F6282_DEV_ID) {
+               if (rev == MV88F6282_REV_A0)
+                       return "MV88F6282-Rev-A0";
+               else
+                       return "MV88F6282-Rev-Unsupported";
        } else {
                return "Device-Unknown";
        }
@@ -949,12 +965,14 @@ void __init kirkwood_init(void)
 static int __init kirkwood_clock_gate(void)
 {
        unsigned int curr = readl(CLOCK_GATING_CTRL);
+       u32 dev, rev;
 
+       kirkwood_pcie_id(&dev, &rev);
        printk(KERN_DEBUG "Gating clock of unused units\n");
        printk(KERN_DEBUG "before: 0x%08x\n", curr);
 
        /* Make sure those units are accessible */
-       writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL);
+       writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL);
 
        /* For SATA: first shutdown the phy */
        if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
@@ -979,6 +997,18 @@ static int __init kirkwood_clock_gate(void)
                writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL);
        }
 
+       /* For PCIe 1: first shutdown the phy */
+       if (dev == MV88F6282_DEV_ID) {
+               if (!(kirkwood_clk_ctrl & CGC_PEX1)) {
+                       writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL);
+                       while (1)
+                               if (readl(PCIE1_STATUS) & 0x1)
+                                       break;
+                       writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL);
+               }
+       } else  /* keep this bit set for devices that don't have PCIe1 */
+               kirkwood_clk_ctrl |= CGC_PEX1;
+
        /* Now gate clock the required units */
        writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL);
        printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL));
index 05e8a8a5692e8150535973105b1f50bed60bcfea..5b2c1c18d641670eed6600753cc1691cb18d7efd 100644 (file)
@@ -18,6 +18,9 @@ struct mvsdio_platform_data;
 struct mtd_partition;
 struct mtd_info;
 
+#define KW_PCIE0       (1 << 0)
+#define KW_PCIE1       (1 << 1)
+
 /*
  * Basic Kirkwood init functions used early by machine-setup.
  */
@@ -34,7 +37,7 @@ void kirkwood_ehci_init(void);
 void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data);
 void kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data);
 void kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq);
-void kirkwood_pcie_init(void);
+void kirkwood_pcie_init(unsigned int portmask);
 void kirkwood_sata_init(struct mv_sata_platform_data *sata_data);
 void kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data);
 void kirkwood_spi_init(void);
index 39bdf4bcace959322cc966d613cc976007dbe020..16f6691e7c685cc6af9266b56bcd0af1265a60ef 100644 (file)
@@ -51,6 +51,14 @@ static struct mvsdio_platform_data db88f6281_mvsdio_data = {
 };
 
 static unsigned int db88f6281_mpp_config[] __initdata = {
+       MPP0_NF_IO2,
+       MPP1_NF_IO3,
+       MPP2_NF_IO4,
+       MPP3_NF_IO5,
+       MPP4_NF_IO6,
+       MPP5_NF_IO7,
+       MPP18_NF_IO0,
+       MPP19_NF_IO1,
        MPP37_GPIO,
        MPP38_GPIO,
        0
@@ -74,9 +82,15 @@ static void __init db88f6281_init(void)
 
 static int __init db88f6281_pci_init(void)
 {
-       if (machine_is_db88f6281_bp())
-               kirkwood_pcie_init();
+       if (machine_is_db88f6281_bp()) {
+               u32 dev, rev;
 
+               kirkwood_pcie_id(&dev, &rev);
+               if (dev == MV88F6282_DEV_ID)
+                       kirkwood_pcie_init(KW_PCIE1 | KW_PCIE0);
+               else
+                       kirkwood_pcie_init(KW_PCIE0);
+       }
        return 0;
 }
 subsys_initcall(db88f6281_pci_init);
index 418f5017c50e1d916468ebc99e5b958a706d98f6..aff0e1327e38f8f360fa25dc5291722a2c7df9fe 100644 (file)
@@ -59,8 +59,9 @@
 #define CGC_SATA1              (1 << 15)
 #define CGC_XOR1               (1 << 16)
 #define CGC_CRYPTO             (1 << 17)
+#define CGC_PEX1               (1 << 18)
 #define CGC_GE1                        (1 << 19)
 #define CGC_TDM                        (1 << 20)
-#define CGC_RESERVED           ((1 << 18) | (0x6 << 21))
+#define CGC_RESERVED           (0x6 << 21)
 
 #endif
index f00a0a45a67e5356bf08d722a4c5bda29b4a57ce..9da2eb59180b2128af2d14bed71091d2bd574b1d 100644 (file)
@@ -23,6 +23,7 @@
 #define IRQ_KIRKWOOD_XOR_10    7
 #define IRQ_KIRKWOOD_XOR_11    8
 #define IRQ_KIRKWOOD_PCIE      9
+#define IRQ_KIRKWOOD_PCIE1     10
 #define IRQ_KIRKWOOD_GE00_SUM  11
 #define IRQ_KIRKWOOD_GE01_SUM  15
 #define IRQ_KIRKWOOD_USB       19
index a15cf0ee22bd802c7aaefb4a04b067540eabcd1b..d141af4c274422a542634b33581f9488385def59 100644 (file)
  * Marvell Kirkwood address maps.
  *
  * phys
- * e0000000    PCIe Memory space
+ * e0000000    PCIe #0 Memory space
+ * e8000000    PCIe #1 Memory space
  * f1000000    on-chip peripheral registers
- * f2000000    PCIe I/O space
- * f3000000    NAND controller address window
- * f4000000    Security Accelerator SRAM
+ * f2000000    PCIe #0 I/O space
+ * f3000000    PCIe #1 I/O space
+ * f4000000    NAND controller address window
+ * f5000000    Security Accelerator SRAM
  *
  * virt                phys            size
- * fee00000    f1000000        1M      on-chip peripheral registers
- * fef00000    f2000000        1M      PCIe I/O space
+ * fed00000    f1000000        1M      on-chip peripheral registers
+ * fee00000    f2000000        1M      PCIe #0 I/O space
+ * fef00000    f3000000        1M      PCIe #1 I/O space
  */
 
-#define KIRKWOOD_SRAM_PHYS_BASE                0xf4000000
+#define KIRKWOOD_SRAM_PHYS_BASE                0xf5000000
 #define KIRKWOOD_SRAM_SIZE             SZ_2K
 
-#define KIRKWOOD_NAND_MEM_PHYS_BASE    0xf3000000
+#define KIRKWOOD_NAND_MEM_PHYS_BASE    0xf4000000
 #define KIRKWOOD_NAND_MEM_SIZE         SZ_1K
 
+#define KIRKWOOD_PCIE1_IO_PHYS_BASE    0xf3000000
+#define KIRKWOOD_PCIE1_IO_VIRT_BASE    0xfef00000
+#define KIRKWOOD_PCIE1_IO_BUS_BASE     0x00000000
+#define KIRKWOOD_PCIE1_IO_SIZE         SZ_1M
+
 #define KIRKWOOD_PCIE_IO_PHYS_BASE     0xf2000000
-#define KIRKWOOD_PCIE_IO_VIRT_BASE     0xfef00000
+#define KIRKWOOD_PCIE_IO_VIRT_BASE     0xfee00000
 #define KIRKWOOD_PCIE_IO_BUS_BASE      0x00000000
 #define KIRKWOOD_PCIE_IO_SIZE          SZ_1M
 
 #define KIRKWOOD_REGS_PHYS_BASE                0xf1000000
-#define KIRKWOOD_REGS_VIRT_BASE                0xfee00000
+#define KIRKWOOD_REGS_VIRT_BASE                0xfed00000
 #define KIRKWOOD_REGS_SIZE             SZ_1M
 
 #define KIRKWOOD_PCIE_MEM_PHYS_BASE    0xe0000000
 #define KIRKWOOD_PCIE_MEM_BUS_BASE     0xe0000000
 #define KIRKWOOD_PCIE_MEM_SIZE         SZ_128M
 
+#define KIRKWOOD_PCIE1_MEM_PHYS_BASE   0xe8000000
+#define KIRKWOOD_PCIE1_MEM_BUS_BASE    0xe8000000
+#define KIRKWOOD_PCIE1_MEM_SIZE                SZ_128M
+
 /*
  * Register Map
  */
@@ -72,6 +84,9 @@
 #define PCIE_VIRT_BASE         (KIRKWOOD_REGS_VIRT_BASE | 0x40000)
 #define PCIE_LINK_CTRL         (PCIE_VIRT_BASE | 0x70)
 #define PCIE_STATUS            (PCIE_VIRT_BASE | 0x1a04)
+#define PCIE1_VIRT_BASE                (KIRKWOOD_REGS_VIRT_BASE | 0x44000)
+#define PCIE1_LINK_CTRL                (PCIE1_VIRT_BASE | 0x70)
+#define PCIE1_STATUS           (PCIE1_VIRT_BASE | 0x1a04)
 
 #define USB_PHYS_BASE          (KIRKWOOD_REGS_PHYS_BASE | 0x50000)
 
 #define MV88F6192_DEV_ID       0x6192
 #define MV88F6192_REV_Z0       0
 #define MV88F6192_REV_A0       2
+#define MV88F6192_REV_A1       3
 
 #define MV88F6180_DEV_ID       0x6180
 #define MV88F6180_REV_A0       2
+#define MV88F6180_REV_A1       3
 
+#define MV88F6282_DEV_ID       0x6282
+#define MV88F6282_REV_A0       0
 #endif
diff --git a/arch/arm/mach-kirkwood/include/mach/leds-ns2.h b/arch/arm/mach-kirkwood/include/mach/leds-ns2.h
new file mode 100644 (file)
index 0000000..e21272e
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * arch/arm/mach-kirkwood/include/mach/leds-ns2.h
+ *
+ * Platform data structure for Network Space v2 LED driver
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_LEDS_NS2_H
+#define __MACH_LEDS_NS2_H
+
+struct ns2_led {
+       const char      *name;
+       const char      *default_trigger;
+       unsigned        cmd;
+       unsigned        slow;
+};
+
+struct ns2_led_platform_data {
+       int             num_leds;
+       struct ns2_led  *leds;
+};
+
+#endif /* __MACH_LEDS_NS2_H */
index a5900f64e38c112e7fb195ea2cdca7281cc64af7..065187d177c6299f12543c3198c23c7cbd8f2476 100644 (file)
@@ -23,7 +23,8 @@ static unsigned int __init kirkwood_variant(void)
 
        kirkwood_pcie_id(&dev, &rev);
 
-       if (dev == MV88F6281_DEV_ID && rev >= MV88F6281_REV_A0)
+       if ((dev == MV88F6281_DEV_ID && rev >= MV88F6281_REV_A0) ||
+           (dev == MV88F6282_DEV_ID))
                return MPP_F6281_MASK;
        if (dev == MV88F6192_DEV_ID && rev >= MV88F6192_REV_A0)
                return MPP_F6192_MASK;
index bc74278ed311c2bef402d6e16d808111669ed96e..9b0a94d85c3ee6b4e2238c0db2e65117f63f44eb 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __KIRKWOOD_MPP_H
 #define __KIRKWOOD_MPP_H
 
-#define MPP(_num, _sel, _in, _out, _F6180, _F6190, _F6192, _F6281) ( \
+#define MPP(_num, _sel, _in, _out, _F6180, _F6190, _F6192, _F6281, _F6282) ( \
        /* MPP number */                ((_num) & 0xff) | \
        /* MPP select value */          (((_sel) & 0xf) << 8) | \
        /* may be input signal */       ((!!(_in)) << 12) | \
        /* available on F6180 */        ((!!(_F6180)) << 14) | \
        /* available on F6190 */        ((!!(_F6190)) << 15) | \
        /* available on F6192 */        ((!!(_F6192)) << 16) | \
-       /* available on F6281 */        ((!!(_F6281)) << 17))
+       /* available on F6281 */        ((!!(_F6281)) << 17) | \
+       /* available on F6282 */        ((!!(_F6282)) << 18))
 
 #define MPP_NUM(x)     ((x) & 0xff)
 #define MPP_SEL(x)     (((x) >> 8) & 0xf)
 
-                               /*   num sel  i  o  6180 6190 6192 6281 */
-
-#define MPP_INPUT_MASK         MPP(  0, 0x0, 1, 0, 0,   0,   0,   0    )
-#define MPP_OUTPUT_MASK                MPP(  0, 0x0, 0, 1, 0,   0,   0,   0    )
-
-#define MPP_F6180_MASK         MPP(  0, 0x0, 0, 0, 1,   0,   0,   0    )
-#define MPP_F6190_MASK         MPP(  0, 0x0, 0, 0, 0,   1,   0,   0    )
-#define MPP_F6192_MASK         MPP(  0, 0x0, 0, 0, 0,   0,   1,   0    )
-#define MPP_F6281_MASK         MPP(  0, 0x0, 0, 0, 0,   0,   0,   1    )
-
-#define MPP0_GPIO              MPP(  0, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP0_NF_IO2            MPP(  0, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP0_SPI_SCn           MPP(  0, 0x2, 0, 1, 1,   1,   1,   1    )
-
-#define MPP1_GPO               MPP(  1, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP1_NF_IO3            MPP(  1, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP1_SPI_MOSI          MPP(  1, 0x2, 0, 1, 1,   1,   1,   1    )
-
-#define MPP2_GPO               MPP(  2, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP2_NF_IO4            MPP(  2, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP2_SPI_SCK           MPP(  2, 0x2, 0, 1, 1,   1,   1,   1    )
-
-#define MPP3_GPO               MPP(  3, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP3_NF_IO5            MPP(  3, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP3_SPI_MISO          MPP(  3, 0x2, 1, 0, 1,   1,   1,   1    )
-
-#define MPP4_GPIO              MPP(  4, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP4_NF_IO6            MPP(  4, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP4_UART0_RXD         MPP(  4, 0x2, 1, 0, 1,   1,   1,   1    )
-#define MPP4_SATA1_ACTn                MPP(  4, 0x5, 0, 1, 0,   0,   1,   1    )
-#define MPP4_PTP_CLK           MPP(  4, 0xd, 1, 0, 1,   1,   1,   1    )
-
-#define MPP5_GPO               MPP(  5, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP5_NF_IO7            MPP(  5, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP5_UART0_TXD         MPP(  5, 0x2, 0, 1, 1,   1,   1,   1    )
-#define MPP5_PTP_TRIG_GEN      MPP(  5, 0x4, 0, 1, 1,   1,   1,   1    )
-#define MPP5_SATA0_ACTn                MPP(  5, 0x5, 0, 1, 0,   1,   1,   1    )
-
-#define MPP6_SYSRST_OUTn       MPP(  6, 0x1, 0, 1, 1,   1,   1,   1    )
-#define MPP6_SPI_MOSI          MPP(  6, 0x2, 0, 1, 1,   1,   1,   1    )
-#define MPP6_PTP_TRIG_GEN      MPP(  6, 0x3, 0, 1, 1,   1,   1,   1    )
-
-#define MPP7_GPO               MPP(  7, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP7_PEX_RST_OUTn      MPP(  7, 0x1, 0, 1, 1,   1,   1,   1    )
-#define MPP7_SPI_SCn           MPP(  7, 0x2, 0, 1, 1,   1,   1,   1    )
-#define MPP7_PTP_TRIG_GEN      MPP(  7, 0x3, 0, 1, 1,   1,   1,   1    )
-
-#define MPP8_GPIO              MPP(  8, 0x0, 1, 1, 1,    1,  1,   1    )
-#define MPP8_TW_SDA            MPP(  8, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP8_UART0_RTS         MPP(  8, 0x2, 0, 1, 1,   1,   1,   1    )
-#define MPP8_UART1_RTS         MPP(  8, 0x3, 0, 1, 1,   1,   1,   1    )
-#define MPP8_MII0_RXERR                MPP(  8, 0x4, 1, 0, 0,   1,   1,   1    )
-#define MPP8_SATA1_PRESENTn    MPP(  8, 0x5, 0, 1, 0,   0,   1,   1    )
-#define MPP8_PTP_CLK           MPP(  8, 0xc, 1, 0, 1,   1,   1,   1    )
-#define MPP8_MII0_COL          MPP(  8, 0xd, 1, 0, 1,   1,   1,   1    )
-
-#define MPP9_GPIO              MPP(  9, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP9_TW_SCK            MPP(  9, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP9_UART0_CTS         MPP(  9, 0x2, 1, 0, 1,   1,   1,   1    )
-#define MPP9_UART1_CTS         MPP(  9, 0x3, 1, 0, 1,   1,   1,   1    )
-#define MPP9_SATA0_PRESENTn    MPP(  9, 0x5, 0, 1, 0,   1,   1,   1    )
-#define MPP9_PTP_EVENT_REQ     MPP(  9, 0xc, 1, 0, 1,   1,   1,   1    )
-#define MPP9_MII0_CRS          MPP(  9, 0xd, 1, 0, 1,   1,   1,   1    )
-
-#define MPP10_GPO              MPP( 10, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP10_SPI_SCK          MPP( 10, 0x2, 0, 1, 1,   1,   1,   1    )
-#define MPP10_UART0_TXD                MPP( 10, 0X3, 0, 1, 1,   1,   1,   1    )
-#define MPP10_SATA1_ACTn       MPP( 10, 0x5, 0, 1, 0,   0,   1,   1    )
-#define MPP10_PTP_TRIG_GEN     MPP( 10, 0xc, 0, 1, 1,   1,   1,   1    )
-
-#define MPP11_GPIO             MPP( 11, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP11_SPI_MISO         MPP( 11, 0x2, 1, 0, 1,   1,   1,   1    )
-#define MPP11_UART0_RXD                MPP( 11, 0x3, 1, 0, 1,   1,   1,   1    )
-#define MPP11_PTP_EVENT_REQ    MPP( 11, 0x4, 1, 0, 1,   1,   1,   1    )
-#define MPP11_PTP_TRIG_GEN     MPP( 11, 0xc, 0, 1, 1,   1,   1,   1    )
-#define MPP11_PTP_CLK          MPP( 11, 0xd, 1, 0, 1,   1,   1,   1    )
-#define MPP11_SATA0_ACTn       MPP( 11, 0x5, 0, 1, 0,   1,   1,   1    )
-
-#define MPP12_GPO              MPP( 12, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP12_SD_CLK           MPP( 12, 0x1, 0, 1, 1,   1,   1,   1    )
-
-#define MPP13_GPIO             MPP( 13, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP13_SD_CMD           MPP( 13, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP13_UART1_TXD                MPP( 13, 0x3, 0, 1, 1,   1,   1,   1    )
-
-#define MPP14_GPIO             MPP( 14, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP14_SD_D0            MPP( 14, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP14_UART1_RXD                MPP( 14, 0x3, 1, 0, 1,   1,   1,   1    )
-#define MPP14_SATA1_PRESENTn   MPP( 14, 0x4, 0, 1, 0,   0,   1,   1    )
-#define MPP14_MII0_COL         MPP( 14, 0xd, 1, 0, 1,   1,   1,   1    )
-
-#define MPP15_GPIO             MPP( 15, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP15_SD_D1            MPP( 15, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP15_UART0_RTS                MPP( 15, 0x2, 0, 1, 1,   1,   1,   1    )
-#define MPP15_UART1_TXD                MPP( 15, 0x3, 0, 1, 1,   1,   1,   1    )
-#define MPP15_SATA0_ACTn       MPP( 15, 0x4, 0, 1, 0,   1,   1,   1    )
-
-#define MPP16_GPIO             MPP( 16, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP16_SD_D2            MPP( 16, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP16_UART0_CTS                MPP( 16, 0x2, 1, 0, 1,   1,   1,   1    )
-#define MPP16_UART1_RXD                MPP( 16, 0x3, 1, 0, 1,   1,   1,   1    )
-#define MPP16_SATA1_ACTn       MPP( 16, 0x4, 0, 1, 0,   0,   1,   1    )
-#define MPP16_MII0_CRS         MPP( 16, 0xd, 1, 0, 1,   1,   1,   1    )
-
-#define MPP17_GPIO             MPP( 17, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP17_SD_D3            MPP( 17, 0x1, 1, 1, 1,   1,   1,   1    )
-#define MPP17_SATA0_PRESENTn   MPP( 17, 0x4, 0, 1, 0,   1,   1,   1    )
-
-#define MPP18_GPO              MPP( 18, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP18_NF_IO0           MPP( 18, 0x1, 1, 1, 1,   1,   1,   1    )
-
-#define MPP19_GPO              MPP( 19, 0x0, 0, 1, 1,   1,   1,   1    )
-#define MPP19_NF_IO1           MPP( 19, 0x1, 1, 1, 1,   1,   1,   1    )
-
-#define MPP20_GPIO             MPP( 20, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP20_TSMP0            MPP( 20, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP20_TDM_CH0_TX_QL    MPP( 20, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP20_GE1_0            MPP( 20, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP20_AUDIO_SPDIFI     MPP( 20, 0x4, 1, 0, 0,   0,   1,   1    )
-#define MPP20_SATA1_ACTn       MPP( 20, 0x5, 0, 1, 0,   0,   1,   1    )
-
-#define MPP21_GPIO             MPP( 21, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP21_TSMP1            MPP( 21, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP21_TDM_CH0_RX_QL    MPP( 21, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP21_GE1_1            MPP( 21, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP21_AUDIO_SPDIFO     MPP( 21, 0x4, 0, 1, 0,   0,   1,   1    )
-#define MPP21_SATA0_ACTn       MPP( 21, 0x5, 0, 1, 0,   1,   1,   1    )
-
-#define MPP22_GPIO             MPP( 22, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP22_TSMP2            MPP( 22, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP22_TDM_CH2_TX_QL    MPP( 22, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP22_GE1_2            MPP( 22, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP22_AUDIO_SPDIFRMKCLK        MPP( 22, 0x4, 0, 1, 0,   0,   1,   1    )
-#define MPP22_SATA1_PRESENTn   MPP( 22, 0x5, 0, 1, 0,   0,   1,   1    )
-
-#define MPP23_GPIO             MPP( 23, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP23_TSMP3            MPP( 23, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP23_TDM_CH2_RX_QL    MPP( 23, 0x2, 1, 0, 0,   0,   1,   1    )
-#define MPP23_GE1_3            MPP( 23, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP23_AUDIO_I2SBCLK    MPP( 23, 0x4, 0, 1, 0,   0,   1,   1    )
-#define MPP23_SATA0_PRESENTn   MPP( 23, 0x5, 0, 1, 0,   1,   1,   1    )
-
-#define MPP24_GPIO             MPP( 24, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP24_TSMP4            MPP( 24, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP24_TDM_SPI_CS0      DEV( 24, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP24_GE1_4            MPP( 24, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP24_AUDIO_I2SDO      MPP( 24, 0x4, 0, 1, 0,   0,   1,   1    )
-
-#define MPP25_GPIO             MPP( 25, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP25_TSMP5            MPP( 25, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP25_TDM_SPI_SCK      MPP( 25, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP25_GE1_5            MPP( 25, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP25_AUDIO_I2SLRCLK   MPP( 25, 0x4, 0, 1, 0,   0,   1,   1    )
-
-#define MPP26_GPIO             MPP( 26, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP26_TSMP6            MPP( 26, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP26_TDM_SPI_MISO     MPP( 26, 0x2, 1, 0, 0,   0,   1,   1    )
-#define MPP26_GE1_6            MPP( 26, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP26_AUDIO_I2SMCLK    MPP( 26, 0x4, 0, 1, 0,   0,   1,   1    )
-
-#define MPP27_GPIO             MPP( 27, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP27_TSMP7            MPP( 27, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP27_TDM_SPI_MOSI     MPP( 27, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP27_GE1_7            MPP( 27, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP27_AUDIO_I2SDI      MPP( 27, 0x4, 1, 0, 0,   0,   1,   1    )
-
-#define MPP28_GPIO             MPP( 28, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP28_TSMP8            MPP( 28, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP28_TDM_CODEC_INTn   MPP( 28, 0x2, 0, 0, 0,   0,   1,   1    )
-#define MPP28_GE1_8            MPP( 28, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP28_AUDIO_EXTCLK     MPP( 28, 0x4, 1, 0, 0,   0,   1,   1    )
-
-#define MPP29_GPIO             MPP( 29, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP29_TSMP9            MPP( 29, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP29_TDM_CODEC_RSTn   MPP( 29, 0x2, 0, 0, 0,   0,   1,   1    )
-#define MPP29_GE1_9            MPP( 29, 0x3, 0, 0, 0,   1,   1,   1    )
-
-#define MPP30_GPIO             MPP( 30, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP30_TSMP10           MPP( 30, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP30_TDM_PCLK         MPP( 30, 0x2, 1, 1, 0,   0,   1,   1    )
-#define MPP30_GE1_10           MPP( 30, 0x3, 0, 0, 0,   1,   1,   1    )
-
-#define MPP31_GPIO             MPP( 31, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP31_TSMP11           MPP( 31, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP31_TDM_FS           MPP( 31, 0x2, 1, 1, 0,   0,   1,   1    )
-#define MPP31_GE1_11           MPP( 31, 0x3, 0, 0, 0,   1,   1,   1    )
-
-#define MPP32_GPIO             MPP( 32, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP32_TSMP12           MPP( 32, 0x1, 1, 1, 0,   0,   1,   1    )
-#define MPP32_TDM_DRX          MPP( 32, 0x2, 1, 0, 0,   0,   1,   1    )
-#define MPP32_GE1_12           MPP( 32, 0x3, 0, 0, 0,   1,   1,   1    )
-
-#define MPP33_GPIO             MPP( 33, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP33_TDM_DTX          MPP( 33, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP33_GE1_13           MPP( 33, 0x3, 0, 0, 0,   1,   1,   1    )
-
-#define MPP34_GPIO             MPP( 34, 0x0, 1, 1, 0,   1,   1,   1    )
-#define MPP34_TDM_SPI_CS1      MPP( 34, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP34_GE1_14           MPP( 34, 0x3, 0, 0, 0,   1,   1,   1    )
-
-#define MPP35_GPIO             MPP( 35, 0x0, 1, 1, 1,   1,   1,   1    )
-#define MPP35_TDM_CH0_TX_QL    MPP( 35, 0x2, 0, 1, 0,   0,   1,   1    )
-#define MPP35_GE1_15           MPP( 35, 0x3, 0, 0, 0,   1,   1,   1    )
-#define MPP35_SATA0_ACTn       MPP( 35, 0x5, 0, 1, 0,   1,   1,   1    )
-#define MPP35_MII0_RXERR       MPP( 35, 0xc, 1, 0, 1,   1,   1,   1    )
-
-#define MPP36_GPIO             MPP( 36, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP36_TSMP0            MPP( 36, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP36_TDM_SPI_CS1      MPP( 36, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP36_AUDIO_SPDIFI     MPP( 36, 0x4, 1, 0, 1,   0,   0,   1    )
-
-#define MPP37_GPIO             MPP( 37, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP37_TSMP1            MPP( 37, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP37_TDM_CH2_TX_QL    MPP( 37, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP37_AUDIO_SPDIFO     MPP( 37, 0x4, 0, 1, 1,   0,   0,   1    )
-
-#define MPP38_GPIO             MPP( 38, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP38_TSMP2            MPP( 38, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP38_TDM_CH2_RX_QL    MPP( 38, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP38_AUDIO_SPDIFRMLCLK        MPP( 38, 0x4, 0, 1, 1,   0,   0,   1    )
-
-#define MPP39_GPIO             MPP( 39, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP39_TSMP3            MPP( 39, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP39_TDM_SPI_CS0      MPP( 39, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP39_AUDIO_I2SBCLK    MPP( 39, 0x4, 0, 1, 1,   0,   0,   1    )
-
-#define MPP40_GPIO             MPP( 40, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP40_TSMP4            MPP( 40, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP40_TDM_SPI_SCK      MPP( 40, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP40_AUDIO_I2SDO      MPP( 40, 0x4, 0, 1, 1,   0,   0,   1    )
-
-#define MPP41_GPIO             MPP( 41, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP41_TSMP5            MPP( 41, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP41_TDM_SPI_MISO     MPP( 41, 0x2, 1, 0, 0,   0,   0,   1    )
-#define MPP41_AUDIO_I2SLRC     MPP( 41, 0x4, 0, 1, 1,   0,   0,   1    )
-
-#define MPP42_GPIO             MPP( 42, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP42_TSMP6            MPP( 42, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP42_TDM_SPI_MOSI     MPP( 42, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP42_AUDIO_I2SMCLK    MPP( 42, 0x4, 0, 1, 1,   0,   0,   1    )
-
-#define MPP43_GPIO             MPP( 43, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP43_TSMP7            MPP( 43, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP43_TDM_CODEC_INTn   MPP( 43, 0x2, 0, 0, 0,   0,   0,   1    )
-#define MPP43_AUDIO_I2SDI      MPP( 43, 0x4, 1, 0, 1,   0,   0,   1    )
-
-#define MPP44_GPIO             MPP( 44, 0x0, 1, 1, 1,   0,   0,   1    )
-#define MPP44_TSMP8            MPP( 44, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP44_TDM_CODEC_RSTn   MPP( 44, 0x2, 0, 0, 0,   0,   0,   1    )
-#define MPP44_AUDIO_EXTCLK     MPP( 44, 0x4, 1, 0, 1,   0,   0,   1    )
-
-#define MPP45_GPIO             MPP( 45, 0x0, 1, 1, 0,   0,   0,   1    )
-#define MPP45_TSMP9            MPP( 45, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP45_TDM_PCLK         MPP( 45, 0x2, 1, 1, 0,   0,   0,   1    )
-
-#define MPP46_GPIO             MPP( 46, 0x0, 1, 1, 0,   0,   0,   1    )
-#define MPP46_TSMP10           MPP( 46, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP46_TDM_FS           MPP( 46, 0x2, 1, 1, 0,   0,   0,   1    )
-
-#define MPP47_GPIO             MPP( 47, 0x0, 1, 1, 0,   0,   0,   1    )
-#define MPP47_TSMP11           MPP( 47, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP47_TDM_DRX          MPP( 47, 0x2, 1, 0, 0,   0,   0,   1    )
-
-#define MPP48_GPIO             MPP( 48, 0x0, 1, 1, 0,   0,   0,   1    )
-#define MPP48_TSMP12           MPP( 48, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP48_TDM_DTX          MPP( 48, 0x2, 0, 1, 0,   0,   0,   1    )
-
-#define MPP49_GPIO             MPP( 49, 0x0, 1, 1, 0,   0,   0,   1    )
-#define MPP49_TSMP9            MPP( 49, 0x1, 1, 1, 0,   0,   0,   1    )
-#define MPP49_TDM_CH0_RX_QL    MPP( 49, 0x2, 0, 1, 0,   0,   0,   1    )
-#define MPP49_PTP_CLK          MPP( 49, 0x5, 1, 0, 0,   0,   0,   1    )
+                               /*   num sel  i  o  6180 6190 6192 6281 6282 */
+
+#define MPP_INPUT_MASK         MPP(  0, 0x0, 1, 0, 0,   0,   0,   0,   0 )
+#define MPP_OUTPUT_MASK                MPP(  0, 0x0, 0, 1, 0,   0,   0,   0,   0 )
+
+#define MPP_F6180_MASK         MPP(  0, 0x0, 0, 0, 1,   0,   0,   0,   0 )
+#define MPP_F6190_MASK         MPP(  0, 0x0, 0, 0, 0,   1,   0,   0,   0 )
+#define MPP_F6192_MASK         MPP(  0, 0x0, 0, 0, 0,   0,   1,   0,   0 )
+#define MPP_F6281_MASK         MPP(  0, 0x0, 0, 0, 0,   0,   0,   1,   0 )
+#define MPP_F6282_MASK         MPP(  0, 0x0, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP0_GPIO              MPP(  0, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP0_NF_IO2            MPP(  0, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP0_SPI_SCn           MPP(  0, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+
+#define MPP1_GPO               MPP(  1, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP1_NF_IO3            MPP(  1, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP1_SPI_MOSI          MPP(  1, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+
+#define MPP2_GPO               MPP(  2, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP2_NF_IO4            MPP(  2, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP2_SPI_SCK           MPP(  2, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+
+#define MPP3_GPO               MPP(  3, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP3_NF_IO5            MPP(  3, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP3_SPI_MISO          MPP(  3, 0x2, 1, 0, 1,   1,   1,   1,   1 )
+
+#define MPP4_GPIO              MPP(  4, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP4_NF_IO6            MPP(  4, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP4_UART0_RXD         MPP(  4, 0x2, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP4_SATA1_ACTn                MPP(  4, 0x5, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP4_LCD_VGA_HSYNC     MPP(  4, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+#define MPP4_PTP_CLK           MPP(  4, 0xd, 1, 0, 1,   1,   1,   1,   0 )
+
+#define MPP5_GPO               MPP(  5, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP5_NF_IO7            MPP(  5, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP5_UART0_TXD         MPP(  5, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP5_PTP_TRIG_GEN      MPP(  5, 0x4, 0, 1, 1,   1,   1,   1,   0 )
+#define MPP5_SATA0_ACTn                MPP(  5, 0x5, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP5_LCD_VGA_VSYNC     MPP(  5, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP6_SYSRST_OUTn       MPP(  6, 0x1, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP6_SPI_MOSI          MPP(  6, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP6_PTP_TRIG_GEN      MPP(  6, 0x3, 0, 1, 1,   1,   1,   1,   0 )
+
+#define MPP7_GPO               MPP(  7, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP7_PEX_RST_OUTn      MPP(  7, 0x1, 0, 1, 1,   1,   1,   1,   0 )
+#define MPP7_SPI_SCn           MPP(  7, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP7_PTP_TRIG_GEN      MPP(  7, 0x3, 0, 1, 1,   1,   1,   1,   0 )
+#define MPP7_LCD_PWM           MPP(  7, 0xb, 0, 1, 0,   0,   0,   0,   1 )
+
+#define MPP8_GPIO              MPP(  8, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP8_TW0_SDA           MPP(  8, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP8_UART0_RTS         MPP(  8, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP8_UART1_RTS         MPP(  8, 0x3, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP8_MII0_RXERR                MPP(  8, 0x4, 1, 0, 0,   1,   1,   1,   1 )
+#define MPP8_SATA1_PRESENTn    MPP(  8, 0x5, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP8_PTP_CLK           MPP(  8, 0xc, 1, 0, 1,   1,   1,   1,   0 )
+#define MPP8_MII0_COL          MPP(  8, 0xd, 1, 0, 1,   1,   1,   1,   1 )
+
+#define MPP9_GPIO              MPP(  9, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP9_TW0_SCK           MPP(  9, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP9_UART0_CTS         MPP(  9, 0x2, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP9_UART1_CTS         MPP(  9, 0x3, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP9_SATA0_PRESENTn    MPP(  9, 0x5, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP9_PTP_EVENT_REQ     MPP(  9, 0xc, 1, 0, 1,   1,   1,   1,   0 )
+#define MPP9_MII0_CRS          MPP(  9, 0xd, 1, 0, 1,   1,   1,   1,   1 )
+
+#define MPP10_GPO              MPP( 10, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP10_SPI_SCK          MPP( 10, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP10_UART0_TXD                MPP( 10, 0X3, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP10_SATA1_ACTn       MPP( 10, 0x5, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP10_PTP_TRIG_GEN     MPP( 10, 0xc, 0, 1, 1,   1,   1,   1,   0 )
+
+#define MPP11_GPIO             MPP( 11, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP11_SPI_MISO         MPP( 11, 0x2, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP11_UART0_RXD                MPP( 11, 0x3, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP11_PTP_EVENT_REQ    MPP( 11, 0x4, 1, 0, 1,   1,   1,   1,   0 )
+#define MPP11_PTP_TRIG_GEN     MPP( 11, 0xc, 0, 1, 1,   1,   1,   1,   0 )
+#define MPP11_PTP_CLK          MPP( 11, 0xd, 1, 0, 1,   1,   1,   1,   0 )
+#define MPP11_SATA0_ACTn       MPP( 11, 0x5, 0, 1, 0,   1,   1,   1,   1 )
+
+#define MPP12_GPO              MPP( 12, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP12_SD_CLK           MPP( 12, 0x1, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP12_AU_SPDIF0                MPP( 12, 0xa, 0, 1, 0,   0,   0,   0,   1 )
+#define MPP12_SPI_MOSI         MPP( 12, 0xb, 0, 1, 0,   0,   0,   0,   1 )
+#define MPP12_TW1_SDA          MPP( 12, 0xd, 1, 0, 0,   0,   0,   0,   1 )
+
+#define MPP13_GPIO             MPP( 13, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP13_SD_CMD           MPP( 13, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP13_UART1_TXD                MPP( 13, 0x3, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP13_AU_SPDIFRMCLK    MPP( 13, 0xa, 0, 1, 0,   0,   0,   0,   1 )
+#define MPP13_LCDPWM           MPP( 13, 0xb, 0, 1, 0,   0,   0,   0,   1 )
+
+#define MPP14_GPIO             MPP( 14, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP14_SD_D0            MPP( 14, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP14_UART1_RXD                MPP( 14, 0x3, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP14_SATA1_PRESENTn   MPP( 14, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP14_AU_SPDIFI                MPP( 14, 0xa, 1, 0, 0,   0,   0,   0,   1 )
+#define MPP14_AU_I2SDI         MPP( 14, 0xb, 1, 0, 0,   0,   0,   0,   1 )
+#define MPP14_MII0_COL         MPP( 14, 0xd, 1, 0, 1,   1,   1,   1,   1 )
+
+#define MPP15_GPIO             MPP( 15, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP15_SD_D1            MPP( 15, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP15_UART0_RTS                MPP( 15, 0x2, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP15_UART1_TXD                MPP( 15, 0x3, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP15_SATA0_ACTn       MPP( 15, 0x4, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP15_SPI_CSn          MPP( 15, 0xb, 0, 1, 0,   0,   0,   0,   1 )
+
+#define MPP16_GPIO             MPP( 16, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP16_SD_D2            MPP( 16, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP16_UART0_CTS                MPP( 16, 0x2, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP16_UART1_RXD                MPP( 16, 0x3, 1, 0, 1,   1,   1,   1,   1 )
+#define MPP16_SATA1_ACTn       MPP( 16, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP16_LCD_EXT_REF_CLK  MPP( 16, 0xb, 1, 0, 0,   0,   0,   0,   1 )
+#define MPP16_MII0_CRS         MPP( 16, 0xd, 1, 0, 1,   1,   1,   1,   1 )
+
+#define MPP17_GPIO             MPP( 17, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP17_SD_D3            MPP( 17, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP17_SATA0_PRESENTn   MPP( 17, 0x4, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP17_SATA1_ACTn       MPP( 17, 0xa, 0, 1, 0,   0,   0,   0,   1 )
+#define MPP17_TW1_SCK          MPP( 17, 0xd, 1, 1, 0,   0,   0,   0,   1 )
+
+#define MPP18_GPO              MPP( 18, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP18_NF_IO0           MPP( 18, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP18_PEX0_CLKREQ      MPP( 18, 0x2, 0, 1, 0,   0,   0,   0,   1 )
+
+#define MPP19_GPO              MPP( 19, 0x0, 0, 1, 1,   1,   1,   1,   1 )
+#define MPP19_NF_IO1           MPP( 19, 0x1, 1, 1, 1,   1,   1,   1,   1 )
+
+#define MPP20_GPIO             MPP( 20, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP20_TSMP0            MPP( 20, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP20_TDM_CH0_TX_QL    MPP( 20, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP20_GE1_TXD0         MPP( 20, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP20_AU_SPDIFI                MPP( 20, 0x4, 1, 0, 0,   0,   1,   1,   1 )
+#define MPP20_SATA1_ACTn       MPP( 20, 0x5, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP20_LCD_D0           MPP( 20, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP21_GPIO             MPP( 21, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP21_TSMP1            MPP( 21, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP21_TDM_CH0_RX_QL    MPP( 21, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP21_GE1_TXD1         MPP( 21, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP21_AU_SPDIFO                MPP( 21, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP21_SATA0_ACTn       MPP( 21, 0x5, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP21_LCD_D1           MPP( 21, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP22_GPIO             MPP( 22, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP22_TSMP2            MPP( 22, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP22_TDM_CH2_TX_QL    MPP( 22, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP22_GE1_TXD2         MPP( 22, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP22_AU_SPDIFRMKCLK   MPP( 22, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP22_SATA1_PRESENTn   MPP( 22, 0x5, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP22_LCD_D2           MPP( 22, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP23_GPIO             MPP( 23, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP23_TSMP3            MPP( 23, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP23_TDM_CH2_RX_QL    MPP( 23, 0x2, 1, 0, 0,   0,   1,   1,   1 )
+#define MPP23_GE1_TXD3         MPP( 23, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP23_AU_I2SBCLK       MPP( 23, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP23_SATA0_PRESENTn   MPP( 23, 0x5, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP23_LCD_D3           MPP( 23, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP24_GPIO             MPP( 24, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP24_TSMP4            MPP( 24, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP24_TDM_SPI_CS0      MPP( 24, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP24_GE1_RXD0         MPP( 24, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP24_AU_I2SDO         MPP( 24, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP24_LCD_D4           MPP( 24, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP25_GPIO             MPP( 25, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP25_TSMP5            MPP( 25, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP25_TDM_SPI_SCK      MPP( 25, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP25_GE1_RXD1         MPP( 25, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP25_AU_I2SLRCLK      MPP( 25, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP25_LCD_D5           MPP( 25, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP26_GPIO             MPP( 26, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP26_TSMP6            MPP( 26, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP26_TDM_SPI_MISO     MPP( 26, 0x2, 1, 0, 0,   0,   1,   1,   1 )
+#define MPP26_GE1_RXD2         MPP( 26, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP26_AU_I2SMCLK       MPP( 26, 0x4, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP26_LCD_D6           MPP( 26, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP27_GPIO             MPP( 27, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP27_TSMP7            MPP( 27, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP27_TDM_SPI_MOSI     MPP( 27, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP27_GE1_RXD3         MPP( 27, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP27_AU_I2SDI         MPP( 27, 0x4, 1, 0, 0,   0,   1,   1,   1 )
+#define MPP27_LCD_D7           MPP( 27, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP28_GPIO             MPP( 28, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP28_TSMP8            MPP( 28, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP28_TDM_CODEC_INTn   MPP( 28, 0x2, 0, 0, 0,   0,   1,   1,   1 )
+#define MPP28_GE1_COL          MPP( 28, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP28_AU_EXTCLK                MPP( 28, 0x4, 1, 0, 0,   0,   1,   1,   1 )
+#define MPP28_LCD_D8           MPP( 28, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP29_GPIO             MPP( 29, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP29_TSMP9            MPP( 29, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP29_TDM_CODEC_RSTn   MPP( 29, 0x2, 0, 0, 0,   0,   1,   1,   1 )
+#define MPP29_GE1_TCLK         MPP( 29, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP29_LCD_D9           MPP( 29, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP30_GPIO             MPP( 30, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP30_TSMP10           MPP( 30, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP30_TDM_PCLK         MPP( 30, 0x2, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP30_GE1_RXCTL                MPP( 30, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP30_LCD_D10          MPP( 30, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP31_GPIO             MPP( 31, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP31_TSMP11           MPP( 31, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP31_TDM_FS           MPP( 31, 0x2, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP31_GE1_RXCLK                MPP( 31, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP31_LCD_D11          MPP( 31, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP32_GPIO             MPP( 32, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP32_TSMP12           MPP( 32, 0x1, 1, 1, 0,   0,   1,   1,   1 )
+#define MPP32_TDM_DRX          MPP( 32, 0x2, 1, 0, 0,   0,   1,   1,   1 )
+#define MPP32_GE1_TCLKOUT      MPP( 32, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP32_LCD_D12          MPP( 32, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP33_GPO              MPP( 33, 0x0, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP33_TDM_DTX          MPP( 33, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP33_GE1_TXCTL                MPP( 33, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP33_LCD_D13          MPP( 33, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP34_GPIO             MPP( 34, 0x0, 1, 1, 0,   1,   1,   1,   1 )
+#define MPP34_TDM_SPI_CS1      MPP( 34, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP34_GE1_TXEN         MPP( 34, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP34_SATA1_ACTn       MPP( 34, 0x5, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP34_LCD_D14          MPP( 34, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP35_GPIO             MPP( 35, 0x0, 1, 1, 1,   1,   1,   1,   1 )
+#define MPP35_TDM_CH0_TX_QL    MPP( 35, 0x2, 0, 1, 0,   0,   1,   1,   1 )
+#define MPP35_GE1_RXERR                MPP( 35, 0x3, 0, 0, 0,   1,   1,   1,   1 )
+#define MPP35_SATA0_ACTn       MPP( 35, 0x5, 0, 1, 0,   1,   1,   1,   1 )
+#define MPP35_LCD_D15          MPP( 22, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+#define MPP35_MII0_RXERR       MPP( 35, 0xc, 1, 0, 1,   1,   1,   1,   1 )
+
+#define MPP36_GPIO             MPP( 36, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP36_TSMP0            MPP( 36, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP36_TDM_SPI_CS1      MPP( 36, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP36_AU_SPDIFI                MPP( 36, 0x4, 1, 0, 1,   0,   0,   1,   1 )
+#define MPP36_TW1_SDA          MPP( 36, 0xb, 1, 1, 0,   0,   0,   0,   1 )
+
+#define MPP37_GPIO             MPP( 37, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP37_TSMP1            MPP( 37, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP37_TDM_CH2_TX_QL    MPP( 37, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP37_AU_SPDIFO                MPP( 37, 0x4, 0, 1, 1,   0,   0,   1,   1 )
+#define MPP37_TW1_SCK          MPP( 37, 0xb, 1, 1, 0,   0,   0,   0,   1 )
+
+#define MPP38_GPIO             MPP( 38, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP38_TSMP2            MPP( 38, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP38_TDM_CH2_RX_QL    MPP( 38, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP38_AU_SPDIFRMLCLK   MPP( 38, 0x4, 0, 1, 1,   0,   0,   1,   1 )
+#define MPP38_LCD_D18          MPP( 38, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP39_GPIO             MPP( 39, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP39_TSMP3            MPP( 39, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP39_TDM_SPI_CS0      MPP( 39, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP39_AU_I2SBCLK       MPP( 39, 0x4, 0, 1, 1,   0,   0,   1,   1 )
+#define MPP39_LCD_D19          MPP( 39, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP40_GPIO             MPP( 40, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP40_TSMP4            MPP( 40, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP40_TDM_SPI_SCK      MPP( 40, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP40_AU_I2SDO         MPP( 40, 0x4, 0, 1, 1,   0,   0,   1,   1 )
+#define MPP40_LCD_D20          MPP( 40, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP41_GPIO             MPP( 41, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP41_TSMP5            MPP( 41, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP41_TDM_SPI_MISO     MPP( 41, 0x2, 1, 0, 0,   0,   0,   1,   1 )
+#define MPP41_AU_I2SLRCLK      MPP( 41, 0x4, 0, 1, 1,   0,   0,   1,   1 )
+#define MPP41_LCD_D21          MPP( 41, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP42_GPIO             MPP( 42, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP42_TSMP6            MPP( 42, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP42_TDM_SPI_MOSI     MPP( 42, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP42_AU_I2SMCLK       MPP( 42, 0x4, 0, 1, 1,   0,   0,   1,   1 )
+#define MPP42_LCD_D22          MPP( 42, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP43_GPIO             MPP( 43, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP43_TSMP7            MPP( 43, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP43_TDM_CODEC_INTn   MPP( 43, 0x2, 0, 0, 0,   0,   0,   1,   1 )
+#define MPP43_AU_I2SDI         MPP( 43, 0x4, 1, 0, 1,   0,   0,   1,   1 )
+#define MPP43_LCD_D23          MPP( 22, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP44_GPIO             MPP( 44, 0x0, 1, 1, 1,   0,   0,   1,   1 )
+#define MPP44_TSMP8            MPP( 44, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP44_TDM_CODEC_RSTn   MPP( 44, 0x2, 0, 0, 0,   0,   0,   1,   1 )
+#define MPP44_AU_EXTCLK                MPP( 44, 0x4, 1, 0, 1,   0,   0,   1,   1 )
+#define MPP44_LCD_CLK          MPP( 44, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP45_GPIO             MPP( 45, 0x0, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP45_TSMP9            MPP( 45, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP45_TDM_PCLK         MPP( 45, 0x2, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP245_LCD_E           MPP( 45, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP46_GPIO             MPP( 46, 0x0, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP46_TSMP10           MPP( 46, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP46_TDM_FS           MPP( 46, 0x2, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP46_LCD_HSYNC                MPP( 46, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP47_GPIO             MPP( 47, 0x0, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP47_TSMP11           MPP( 47, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP47_TDM_DRX          MPP( 47, 0x2, 1, 0, 0,   0,   0,   1,   1 )
+#define MPP47_LCD_VSYNC                MPP( 47, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP48_GPIO             MPP( 48, 0x0, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP48_TSMP12           MPP( 48, 0x1, 1, 1, 0,   0,   0,   1,   1 )
+#define MPP48_TDM_DTX          MPP( 48, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP48_LCD_D16          MPP( 22, 0xb, 0, 0, 0,   0,   0,   0,   1 )
+
+#define MPP49_GPIO             MPP( 49, 0x0, 1, 1, 0,   0,   0,   1,   0 )
+#define MPP49_GPO              MPP( 49, 0x0, 0, 1, 0,   0,   0,   0,   1 )
+#define MPP49_TSMP9            MPP( 49, 0x1, 1, 1, 0,   0,   0,   1,   0 )
+#define MPP49_TDM_CH0_RX_QL    MPP( 49, 0x2, 0, 1, 0,   0,   0,   1,   1 )
+#define MPP49_PTP_CLK          MPP( 49, 0x5, 1, 0, 0,   0,   0,   1,   0 )
+#define MPP49_PEX0_CLKREQ      MPP( 49, 0xa, 0, 1, 0,   0,   0,   0,   1 )
+#define MPP49_LCD_D17          MPP( 49, 0xb, 0, 0, 0,   0,   0,   0,   1 )
 
 #define MPP_MAX                        49
 
index 5e6f711b1c6753713b8819078ec0bc053566f200..c6b92b42eb4e5a627fcceb74b61078bc8e589f4a 100644 (file)
@@ -155,7 +155,7 @@ static void __init mv88f6281gtw_ge_init(void)
 static int __init mv88f6281gtw_ge_pci_init(void)
 {
        if (machine_is_mv88f6281gtw_ge())
-               kirkwood_pcie_init();
+               kirkwood_pcie_init(KW_PCIE0);
 
        return 0;
 }
index 3ae158d72681f13a2a6f9e0246c08e3a3f618d3a..d26bf324738bde48e5be8b5c5cf13978a9f03730 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/kirkwood.h>
+#include <mach/leds-ns2.h>
 #include <plat/time.h>
 #include "common.h"
 #include "mpp.h"
@@ -126,6 +127,18 @@ static void __init netspace_v2_sata_power_init(void)
        }
        if (err)
                pr_err("netspace_v2: failed to setup SATA0 power\n");
+
+       if (machine_is_netspace_max_v2()) {
+               err = gpio_request(NETSPACE_V2_GPIO_SATA1_POWER, "SATA1 power");
+               if (err == 0) {
+                       err = gpio_direction_output(
+                                       NETSPACE_V2_GPIO_SATA1_POWER, 1);
+                       if (err)
+                               gpio_free(NETSPACE_V2_GPIO_SATA1_POWER);
+               }
+               if (err)
+                       pr_err("netspace_v2: failed to setup SATA1 power\n");
+       }
 }
 
 /*****************************************************************************
@@ -160,36 +173,12 @@ static struct platform_device netspace_v2_gpio_buttons = {
  * GPIO LEDs
  ****************************************************************************/
 
-/*
- * The blue front LED is wired to a CPLD and can blink in relation with the
- * SATA activity.
- *
- * The following array detail the different LED registers and the combination
- * of their possible values:
- *
- *  cmd_led   |  slow_led  | /SATA active | LED state
- *            |            |              |
- *     1      |     0      |      x       |  off
- *     -      |     1      |      x       |  on
- *     0      |     0      |      1       |  on
- *     0      |     0      |      0       |  blink (rate 300ms)
- */
-
 #define NETSPACE_V2_GPIO_RED_LED       12
-#define NETSPACE_V2_GPIO_BLUE_LED_SLOW 29
-#define NETSPACE_V2_GPIO_BLUE_LED_CMD  30
-
 
 static struct gpio_led netspace_v2_gpio_led_pins[] = {
        {
-               .name                   = "ns_v2:blue:sata",
-               .default_trigger        = "default-on",
-               .gpio                   = NETSPACE_V2_GPIO_BLUE_LED_CMD,
-               .active_low             = 1,
-       },
-       {
-               .name                   = "ns_v2:red:fail",
-               .gpio                   = NETSPACE_V2_GPIO_RED_LED,
+               .name   = "ns_v2:red:fail",
+               .gpio   = NETSPACE_V2_GPIO_RED_LED,
        },
 };
 
@@ -206,22 +195,33 @@ static struct platform_device netspace_v2_gpio_leds = {
        },
 };
 
-static void __init netspace_v2_gpio_leds_init(void)
-{
-       int err;
+/*****************************************************************************
+ * Dual-GPIO CPLD LEDs
+ ****************************************************************************/
 
-       /* Configure register slow_led to allow SATA activity LED blinking */
-       err = gpio_request(NETSPACE_V2_GPIO_BLUE_LED_SLOW, "blue LED slow");
-       if (err == 0) {
-               err = gpio_direction_output(NETSPACE_V2_GPIO_BLUE_LED_SLOW, 0);
-               if (err)
-                       gpio_free(NETSPACE_V2_GPIO_BLUE_LED_SLOW);
-       }
-       if (err)
-               pr_err("netspace_v2: failed to configure blue LED slow GPIO\n");
+#define NETSPACE_V2_GPIO_BLUE_LED_SLOW 29
+#define NETSPACE_V2_GPIO_BLUE_LED_CMD  30
 
-       platform_device_register(&netspace_v2_gpio_leds);
-}
+static struct ns2_led netspace_v2_led_pins[] = {
+       {
+               .name   = "ns_v2:blue:sata",
+               .cmd    = NETSPACE_V2_GPIO_BLUE_LED_CMD,
+               .slow   = NETSPACE_V2_GPIO_BLUE_LED_SLOW,
+       },
+};
+
+static struct ns2_led_platform_data netspace_v2_leds_data = {
+       .num_leds       = ARRAY_SIZE(netspace_v2_led_pins),
+       .leds           = netspace_v2_led_pins,
+};
+
+static struct platform_device netspace_v2_leds = {
+       .name           = "leds-ns2",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &netspace_v2_leds_data,
+       },
+};
 
 /*****************************************************************************
  * Timer
@@ -249,17 +249,21 @@ static unsigned int netspace_v2_mpp_config[] __initdata = {
        MPP4_NF_IO6,
        MPP5_NF_IO7,
        MPP6_SYSRST_OUTn,
-       MPP8_TW_SDA,
-       MPP9_TW_SCK,
+       MPP7_GPO,               /* Fan speed (bit 1) */
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
        MPP10_UART0_TXD,
        MPP11_UART0_RXD,
        MPP12_GPO,              /* Red led */
        MPP14_GPIO,             /* USB fuse */
        MPP16_GPIO,             /* SATA 0 power */
+       MPP17_GPIO,             /* SATA 1 power */
        MPP18_NF_IO0,
        MPP19_NF_IO1,
        MPP20_SATA1_ACTn,
        MPP21_SATA0_ACTn,
+       MPP22_GPIO,             /* Fan speed (bit 0) */
+       MPP23_GPIO,             /* Fan power */
        MPP24_GPIO,             /* USB mode select */
        MPP25_GPIO,             /* Fan rotation fail */
        MPP26_GPIO,             /* USB device vbus */
@@ -268,6 +272,7 @@ static unsigned int netspace_v2_mpp_config[] __initdata = {
        MPP30_GPIO,             /* Blue led (command register) */
        MPP31_GPIO,             /* Board power off */
        MPP32_GPIO,             /* Power button (0 = Released, 1 = Pushed) */
+       MPP33_GPO,              /* Fan speed (bit 2) */
        0
 };
 
@@ -299,7 +304,8 @@ static void __init netspace_v2_init(void)
        i2c_register_board_info(0, netspace_v2_i2c_info,
                                ARRAY_SIZE(netspace_v2_i2c_info));
 
-       netspace_v2_gpio_leds_init();
+       platform_device_register(&netspace_v2_leds);
+       platform_device_register(&netspace_v2_gpio_leds);
        platform_device_register(&netspace_v2_gpio_buttons);
 
        if (gpio_request(NETSPACE_V2_GPIO_POWER_OFF, "power-off") == 0 &&
@@ -332,3 +338,15 @@ MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
        .timer          = &netspace_v2_timer,
 MACHINE_END
 #endif
+
+#ifdef CONFIG_MACH_NETSPACE_MAX_V2
+MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
+       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
+       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = netspace_v2_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &netspace_v2_timer,
+MACHINE_END
+#endif
index 8a2bb0228e4f1d73b26b266d5e9c07bae49049ef..2bd14c5079de7c0e7379439523aed3422173f383 100644 (file)
@@ -270,8 +270,8 @@ static unsigned int net2big_v2_mpp_config[] __initdata = {
        MPP3_SPI_MISO,
        MPP6_SYSRST_OUTn,
        MPP7_GPO,               /* Request power-off */
-       MPP8_TW_SDA,
-       MPP9_TW_SCK,
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
        MPP10_UART0_TXD,
        MPP11_UART0_RXD,
        MPP13_GPIO,             /* Rear power switch (on|auto) */
@@ -306,8 +306,8 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
        MPP3_SPI_MISO,
        MPP6_SYSRST_OUTn,
        MPP7_GPO,               /* Request power-off */
-       MPP8_TW_SDA,
-       MPP9_TW_SCK,
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
        MPP10_UART0_TXD,
        MPP11_UART0_RXD,
        MPP13_GPIO,             /* Rear power switch (on|auto) */
@@ -315,20 +315,20 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
        MPP15_GPIO,             /* Rear power switch (auto|off) */
        MPP16_GPIO,             /* SATA HDD1 power */
        MPP17_GPIO,             /* SATA HDD2 power */
-       MPP20_GE1_0,
-       MPP21_GE1_1,
-       MPP22_GE1_2,
-       MPP23_GE1_3,
-       MPP24_GE1_4,
-       MPP25_GE1_5,
-       MPP26_GE1_6,
-       MPP27_GE1_7,
+       MPP20_GE1_TXD0,
+       MPP21_GE1_TXD1,
+       MPP22_GE1_TXD2,
+       MPP23_GE1_TXD3,
+       MPP24_GE1_RXD0,
+       MPP25_GE1_RXD1,
+       MPP26_GE1_RXD2,
+       MPP27_GE1_RXD3,
        MPP28_GPIO,             /* USB enable host vbus */
        MPP29_GPIO,             /* CPLD extension ALE */
-       MPP30_GE1_10,
-       MPP31_GE1_11,
-       MPP32_GE1_12,
-       MPP33_GE1_13,
+       MPP30_GE1_RXCTL,
+       MPP31_GE1_RXCLK,
+       MPP32_GE1_TCLKOUT,
+       MPP33_GE1_TXCTL,
        MPP34_GPIO,             /* Rear Push button */
        MPP35_GPIO,             /* Inhibit switch power-off */
        MPP36_GPIO,             /* SATA HDD1 presence */
index ad3f1ec3379689556296ef1ccf3b425c07f8007a..fd64cd2b4e0ad0cd8780ef33f25f5821407d49c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-kirkwood/openrd-setup.c
  *
- * Marvell OpenRD (Base|Client) Board Setup
+ * Marvell OpenRD (Base|Client|Ultimate) Board Setup
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
@@ -73,9 +73,15 @@ static void __init openrd_init(void)
 
        kirkwood_ehci_init();
 
+       if (machine_is_openrd_ultimate()) {
+               openrd_ge00_data.phy_addr = MV643XX_ETH_PHY_ADDR(0);
+               openrd_ge01_data.phy_addr = MV643XX_ETH_PHY_ADDR(1);
+       }
+
        kirkwood_ge00_init(&openrd_ge00_data);
-       if (machine_is_openrd_client())
+       if (!machine_is_openrd_base())
                kirkwood_ge01_init(&openrd_ge01_data);
+
        kirkwood_sata_init(&openrd_sata_data);
        kirkwood_sdio_init(&openrd_mvsdio_data);
 
@@ -84,8 +90,10 @@ static void __init openrd_init(void)
 
 static int __init openrd_pci_init(void)
 {
-       if (machine_is_openrd_base() || machine_is_openrd_client())
-               kirkwood_pcie_init();
+       if (machine_is_openrd_base() ||
+           machine_is_openrd_client() ||
+           machine_is_openrd_ultimate())
+               kirkwood_pcie_init(KW_PCIE0);
 
        return 0;
 }
@@ -116,3 +124,16 @@ MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
        .timer          = &kirkwood_timer,
 MACHINE_END
 #endif
+
+#ifdef CONFIG_MACH_OPENRD_ULTIMATE
+MACHINE_START(OPENRD_ULTIMATE, "Marvell OpenRD Ultimate Board")
+       /* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
+       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
+       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = openrd_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &kirkwood_timer,
+MACHINE_END
+#endif
index dee1eff50d3933d2252a2f66aed2f1d7456d69c3..55e7f00836b7cdba68a9662729119e977904a2dd 100644 (file)
 #include <mach/bridge-regs.h>
 #include "common.h"
 
+void __init kirkwood_pcie_id(u32 *dev, u32 *rev)
+{
+       *dev = orion_pcie_dev_id((void __iomem *)PCIE_VIRT_BASE);
+       *rev = orion_pcie_rev((void __iomem *)PCIE_VIRT_BASE);
+}
 
-#define PCIE_BASE      ((void __iomem *)PCIE_VIRT_BASE)
+struct pcie_port {
+       u8                      root_bus_nr;
+       void __iomem            *base;
+       spinlock_t              conf_lock;
+       int                     irq;
+       struct resource         res[2];
+};
 
-void __init kirkwood_pcie_id(u32 *dev, u32 *rev)
+static int pcie_port_map[2];
+static int num_pcie_ports;
+
+static inline struct pcie_port *bus_to_port(struct pci_bus *bus)
 {
-       *dev = orion_pcie_dev_id(PCIE_BASE);
-       *rev = orion_pcie_rev(PCIE_BASE);
+       struct pci_sys_data *sys = bus->sysdata;
+       return sys->private_data;
 }
 
-static int pcie_valid_config(int bus, int dev)
+static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
 {
        /*
         * Don't go out when trying to access --
         * 1. nonexisting device on local bus
         * 2. where there's no device connected (no link)
         */
-       if (bus == 0 && dev == 0)
+       if (bus == pp->root_bus_nr && dev == 0)
                return 1;
 
-       if (!orion_pcie_link_up(PCIE_BASE))
+       if (!orion_pcie_link_up(pp->base))
                return 0;
 
-       if (bus == 0 && dev != 1)
+       if (bus == pp->root_bus_nr && dev != 1)
                return 0;
 
        return 1;
@@ -52,22 +66,22 @@ static int pcie_valid_config(int bus, int dev)
  * and then reading the PCIE_CONF_DATA register. Need to make sure these
  * transactions are atomic.
  */
-static DEFINE_SPINLOCK(kirkwood_pcie_lock);
 
 static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
                        int size, u32 *val)
 {
+       struct pcie_port *pp = bus_to_port(bus);
        unsigned long flags;
        int ret;
 
-       if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) {
+       if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
                *val = 0xffffffff;
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
 
-       spin_lock_irqsave(&kirkwood_pcie_lock, flags);
-       ret = orion_pcie_rd_conf(PCIE_BASE, bus, devfn, where, size, val);
-       spin_unlock_irqrestore(&kirkwood_pcie_lock, flags);
+       spin_lock_irqsave(&pp->conf_lock, flags);
+       ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
+       spin_unlock_irqrestore(&pp->conf_lock, flags);
 
        return ret;
 }
@@ -75,15 +89,16 @@ static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
                        int where, int size, u32 val)
 {
+       struct pcie_port *pp = bus_to_port(bus);
        unsigned long flags;
        int ret;
 
-       if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0)
+       if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       spin_lock_irqsave(&kirkwood_pcie_lock, flags);
-       ret = orion_pcie_wr_conf(PCIE_BASE, bus, devfn, where, size, val);
-       spin_unlock_irqrestore(&kirkwood_pcie_lock, flags);
+       spin_lock_irqsave(&pp->conf_lock, flags);
+       ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
+       spin_unlock_irqrestore(&pp->conf_lock, flags);
 
        return ret;
 }
@@ -93,50 +108,98 @@ static struct pci_ops pcie_ops = {
        .write = pcie_wr_conf,
 };
 
-
-static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
+static void __init pcie0_ioresources_init(struct pcie_port *pp)
 {
-       struct resource *res;
-       extern unsigned int kirkwood_clk_ctrl;
+       pp->base = (void __iomem *)PCIE_VIRT_BASE;
+       pp->irq = IRQ_KIRKWOOD_PCIE;
 
        /*
-        * Generic PCIe unit setup.
+        * IORESOURCE_IO
         */
-       orion_pcie_setup(PCIE_BASE, &kirkwood_mbus_dram_info);
+       pp->res[0].name = "PCIe 0 I/O Space";
+       pp->res[0].start = KIRKWOOD_PCIE_IO_PHYS_BASE;
+       pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
+       pp->res[0].flags = IORESOURCE_IO;
 
        /*
-        * Request resources.
+        * IORESOURCE_MEM
         */
-       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
-       if (!res)
-               panic("pcie_setup unable to alloc resources");
+       pp->res[1].name = "PCIe 0 MEM";
+       pp->res[1].start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
+       pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
+       pp->res[1].flags = IORESOURCE_MEM;
+}
+
+static void __init pcie1_ioresources_init(struct pcie_port *pp)
+{
+       pp->base = (void __iomem *)PCIE1_VIRT_BASE;
+       pp->irq = IRQ_KIRKWOOD_PCIE1;
 
        /*
         * IORESOURCE_IO
         */
-       res[0].name = "PCIe I/O Space";
-       res[0].flags = IORESOURCE_IO;
-       res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
-       res[0].end = res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
-       if (request_resource(&ioport_resource, &res[0]))
-               panic("Request PCIe IO resource failed\n");
-       sys->resource[0] = &res[0];
+       pp->res[0].name = "PCIe 1 I/O Space";
+       pp->res[0].start = KIRKWOOD_PCIE1_IO_PHYS_BASE;
+       pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1;
+       pp->res[0].flags = IORESOURCE_IO;
 
        /*
         * IORESOURCE_MEM
         */
-       res[1].name = "PCIe Memory Space";
-       res[1].flags = IORESOURCE_MEM;
-       res[1].start = KIRKWOOD_PCIE_MEM_BUS_BASE;
-       res[1].end = res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
-       if (request_resource(&iomem_resource, &res[1]))
-               panic("Request PCIe Memory resource failed\n");
-       sys->resource[1] = &res[1];
+       pp->res[1].name = "PCIe 1 MEM";
+       pp->res[1].start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
+       pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
+       pp->res[1].flags = IORESOURCE_MEM;
+}
+
+static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+       extern unsigned int kirkwood_clk_ctrl;
+       struct pcie_port *pp;
+       int index;
 
+       if (nr >= num_pcie_ports)
+               return 0;
+
+       index = pcie_port_map[nr];
+       printk(KERN_INFO "PCI: bus%d uses PCIe port %d\n", sys->busnr, index);
+
+       pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+       if (!pp)
+               panic("PCIe: failed to allocate pcie_port data");
+       sys->private_data = pp;
+       pp->root_bus_nr = sys->busnr;
+       spin_lock_init(&pp->conf_lock);
+
+       switch (index) {
+       case 0:
+               kirkwood_clk_ctrl |= CGC_PEX0;
+               pcie0_ioresources_init(pp);
+               break;
+       case 1:
+               kirkwood_clk_ctrl |= CGC_PEX1;
+               pcie1_ioresources_init(pp);
+               break;
+       default:
+               panic("PCIe setup: invalid controller %d", index);
+       }
+
+       if (request_resource(&ioport_resource, &pp->res[0]))
+               panic("Request PCIe%d IO resource failed\n", index);
+       if (request_resource(&iomem_resource, &pp->res[1]))
+               panic("Request PCIe%d Memory resource failed\n", index);
+
+       sys->resource[0] = &pp->res[0];
+       sys->resource[1] = &pp->res[1];
        sys->resource[2] = NULL;
        sys->io_offset = 0;
 
-       kirkwood_clk_ctrl |= CGC_PEX0;
+       /*
+        * Generic PCIe unit setup.
+        */
+       orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
+
+       orion_pcie_setup(pp->base, &kirkwood_mbus_dram_info);
 
        return 1;
 }
@@ -163,7 +226,7 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 {
        struct pci_bus *bus;
 
-       if (nr == 0) {
+       if (nr < num_pcie_ports) {
                bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
        } else {
                bus = NULL;
@@ -175,18 +238,37 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 
 static int __init kirkwood_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
-       return IRQ_KIRKWOOD_PCIE;
+       struct pcie_port *pp = bus_to_port(dev->bus);
+
+       return pp->irq;
 }
 
 static struct hw_pci kirkwood_pci __initdata = {
-       .nr_controllers = 1,
        .swizzle        = pci_std_swizzle,
        .setup          = kirkwood_pcie_setup,
        .scan           = kirkwood_pcie_scan_bus,
        .map_irq        = kirkwood_pcie_map_irq,
 };
 
-void __init kirkwood_pcie_init(void)
+static void __init add_pcie_port(int index, unsigned long base)
 {
+       printk(KERN_INFO "Kirkwood PCIe port %d: ", index);
+
+       if (orion_pcie_link_up((void __iomem *)base)) {
+               printk(KERN_INFO "link up\n");
+               pcie_port_map[num_pcie_ports++] = index;
+       } else
+               printk(KERN_INFO "link down, ignoring\n");
+}
+
+void __init kirkwood_pcie_init(unsigned int portmask)
+{
+       if (portmask & KW_PCIE0)
+               add_pcie_port(0, PCIE_VIRT_BASE);
+
+       if (portmask & KW_PCIE1)
+               add_pcie_port(1, PCIE1_VIRT_BASE);
+
+       kirkwood_pci.nr_controllers = num_pcie_ports;
        pci_common_init(&kirkwood_pci);
 }
index 3bf6304158f64354b410461c87d9ec0778ba26cf..c34718c2cfe511373df10338e28c399a092c7744 100644 (file)
@@ -71,7 +71,7 @@ static void __init rd88f6192_init(void)
 static int __init rd88f6192_pci_init(void)
 {
        if (machine_is_rd88f6192_nas())
-               kirkwood_pcie_init();
+               kirkwood_pcie_init(KW_PCIE0);
 
        return 0;
 }
index 31708ddbc83e13d5d97b31bdbaf3c13eeb735c1a..3d1477135e12d8fb0edacb8067304a18f04bc111 100644 (file)
@@ -107,7 +107,7 @@ static void __init rd88f6281_init(void)
 static int __init rd88f6281_pci_init(void)
 {
        if (machine_is_rd88f6281())
-               kirkwood_pcie_init();
+               kirkwood_pcie_init(KW_PCIE0);
 
        return 0;
 }
diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c
new file mode 100644 (file)
index 0000000..d01bf89
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *
+ * HP t5325 Thin Client setup
+ *
+ * Copyright (C) 2010  Martin Michlmayr <tbm@cyrius.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/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/i2c.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/ata_platform.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+struct mtd_partition hp_t5325_partitions[] = {
+       {
+               .name           = "u-boot env",
+               .size           = SZ_64K,
+               .offset         = SZ_512K + SZ_256K,
+       },
+       {
+               .name           = "permanent u-boot env",
+               .size           = SZ_64K,
+               .offset         = MTDPART_OFS_APPEND,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       {
+               .name           = "HP env",
+               .size           = SZ_64K,
+               .offset         = MTDPART_OFS_APPEND,
+       },
+       {
+               .name           = "u-boot",
+               .size           = SZ_512K,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       {
+               .name           = "SSD firmware",
+               .size           = SZ_256K,
+               .offset         = SZ_512K,
+       },
+};
+
+const struct flash_platform_data hp_t5325_flash = {
+       .type           = "mx25l8005",
+       .name           = "spi_flash",
+       .parts          = hp_t5325_partitions,
+       .nr_parts       = ARRAY_SIZE(hp_t5325_partitions),
+};
+
+struct spi_board_info __initdata hp_t5325_spi_slave_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &hp_t5325_flash,
+               .irq            = -1,
+       },
+};
+
+static struct mv643xx_eth_platform_data hp_t5325_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
+};
+
+static struct mv_sata_platform_data hp_t5325_sata_data = {
+       .n_ports        = 2,
+};
+
+static struct gpio_keys_button hp_t5325_buttons[] = {
+       {
+               .code           = KEY_POWER,
+               .gpio           = 45,
+               .desc           = "Power",
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data hp_t5325_button_data = {
+       .buttons        = hp_t5325_buttons,
+       .nbuttons       = ARRAY_SIZE(hp_t5325_buttons),
+};
+
+static struct platform_device hp_t5325_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &hp_t5325_button_data,
+       }
+};
+
+static unsigned int hp_t5325_mpp_config[] __initdata = {
+       MPP0_NF_IO2,
+       MPP1_SPI_MOSI,
+       MPP2_SPI_SCK,
+       MPP3_SPI_MISO,
+       MPP4_NF_IO6,
+       MPP5_NF_IO7,
+       MPP6_SYSRST_OUTn,
+       MPP7_SPI_SCn,
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
+       MPP10_UART0_TXD,
+       MPP11_UART0_RXD,
+       MPP12_SD_CLK,
+       MPP13_GPIO,
+       MPP14_GPIO,
+       MPP15_GPIO,
+       MPP16_GPIO,
+       MPP17_GPIO,
+       MPP18_NF_IO0,
+       MPP19_NF_IO1,
+       MPP20_GPIO,
+       MPP21_GPIO,
+       MPP22_GPIO,
+       MPP23_GPIO,
+       MPP32_GPIO,
+       MPP33_GE1_TXCTL,
+       MPP39_AU_I2SBCLK,
+       MPP40_AU_I2SDO,
+       MPP41_AU_I2SLRCLK,
+       MPP42_AU_I2SMCLK,
+       MPP45_GPIO,             /* Power button */
+       MPP48_GPIO,             /* Board power off */
+       0
+};
+
+#define HP_T5325_GPIO_POWER_OFF                48
+
+static void hp_t5325_power_off(void)
+{
+       gpio_set_value(HP_T5325_GPIO_POWER_OFF, 1);
+}
+
+static void __init hp_t5325_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_init();
+       kirkwood_mpp_conf(hp_t5325_mpp_config);
+
+       kirkwood_uart0_init();
+       spi_register_board_info(hp_t5325_spi_slave_info,
+                               ARRAY_SIZE(hp_t5325_spi_slave_info));
+       kirkwood_spi_init();
+       kirkwood_i2c_init();
+       kirkwood_ge00_init(&hp_t5325_ge00_data);
+       kirkwood_sata_init(&hp_t5325_sata_data);
+       kirkwood_ehci_init();
+       platform_device_register(&hp_t5325_button_device);
+
+       if (gpio_request(HP_T5325_GPIO_POWER_OFF, "power-off") == 0 &&
+           gpio_direction_output(HP_T5325_GPIO_POWER_OFF, 0) == 0)
+               pm_power_off = hp_t5325_power_off;
+       else
+               pr_err("t5325: failed to configure power-off GPIO\n");
+}
+
+static int __init hp_t5325_pci_init(void)
+{
+       if (machine_is_t5325())
+               kirkwood_pcie_init(KW_PCIE0);
+
+       return 0;
+}
+subsys_initcall(hp_t5325_pci_init);
+
+MACHINE_START(T5325, "HP t5325 Thin Client")
+       /* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
+       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
+       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = hp_t5325_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &kirkwood_timer,
+MACHINE_END
index 2830f0fe80e09d0b37c14a9589972a012cc733b2..a5bd7fde04a9429068f856070225cf816b96bb56 100644 (file)
@@ -74,8 +74,8 @@ static unsigned int qnap_ts219_mpp_config[] __initdata = {
        MPP3_SPI_MISO,
        MPP4_SATA1_ACTn,
        MPP5_SATA0_ACTn,
-       MPP8_TW_SDA,
-       MPP9_TW_SCK,
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
        MPP10_UART0_TXD,
        MPP11_UART0_RXD,
        MPP13_UART1_TXD,        /* PIC controller */
@@ -83,6 +83,7 @@ static unsigned int qnap_ts219_mpp_config[] __initdata = {
        MPP15_GPIO,             /* USB Copy button */
        MPP16_GPIO,             /* Reset button */
        MPP36_GPIO,             /* RAM: 0: 256 MB, 1: 512 MB */
+       MPP44_GPIO,             /* Board ID: 0: TS-11x, 1: TS-21x */
        0
 };
 
@@ -110,10 +111,10 @@ static void __init qnap_ts219_init(void)
 
 static int __init ts219_pci_init(void)
 {
-   if (machine_is_ts219())
-           kirkwood_pcie_init();
+       if (machine_is_ts219())
+               kirkwood_pcie_init(KW_PCIE0);
 
-   return 0;
+       return 0;
 }
 subsys_initcall(ts219_pci_init);
 
index de49c2d9e74b0b262072721630aeac92f6a57e7a..2e14afef07a2ace0708e144b98bf4ef1f2a446b1 100644 (file)
@@ -2,7 +2,7 @@
  *
  * QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS Board Setup
  *
- * Copyright (C) 2009  Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2009-2010  Martin Michlmayr <tbm@cyrius.com>
  * Copyright (C) 2008  Byron Bradley <byron.bbradley@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
+#include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <asm/mach-types.h>
@@ -26,6 +27,8 @@
 #include "mpp.h"
 #include "tsx1x-common.h"
 
+#define QNAP_TS41X_JUMPER_JP1  45
+
 static struct i2c_board_info __initdata qnap_ts41x_i2c_rtc = {
        I2C_BOARD_INFO("s35390a", 0x30),
 };
@@ -78,31 +81,31 @@ static unsigned int qnap_ts41x_mpp_config[] __initdata = {
        MPP3_SPI_MISO,
        MPP6_SYSRST_OUTn,
        MPP7_PEX_RST_OUTn,
-       MPP8_TW_SDA,
-       MPP9_TW_SCK,
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
        MPP10_UART0_TXD,
        MPP11_UART0_RXD,
        MPP13_UART1_TXD,        /* PIC controller */
        MPP14_UART1_RXD,        /* PIC controller */
        MPP15_SATA0_ACTn,
        MPP16_SATA1_ACTn,
-       MPP20_GE1_0,
-       MPP21_GE1_1,
-       MPP22_GE1_2,
-       MPP23_GE1_3,
-       MPP24_GE1_4,
-       MPP25_GE1_5,
-       MPP26_GE1_6,
-       MPP27_GE1_7,
-       MPP30_GE1_10,
-       MPP31_GE1_11,
-       MPP32_GE1_12,
-       MPP33_GE1_13,
+       MPP20_GE1_TXD0,
+       MPP21_GE1_TXD1,
+       MPP22_GE1_TXD2,
+       MPP23_GE1_TXD3,
+       MPP24_GE1_RXD0,
+       MPP25_GE1_RXD1,
+       MPP26_GE1_RXD2,
+       MPP27_GE1_RXD3,
+       MPP30_GE1_RXCTL,
+       MPP31_GE1_RXCLK,
+       MPP32_GE1_TCLKOUT,
+       MPP33_GE1_TXCTL,
        MPP36_GPIO,             /* RAM: 0: 256 MB, 1: 512 MB */
        MPP37_GPIO,             /* Reset button */
        MPP43_GPIO,             /* USB Copy button */
        MPP44_GPIO,             /* Board ID: 0: TS-419U, 1: TS-419 */
-       MPP45_GPIO,             /* JP1: 0: console, 1: LCD */
+       MPP45_GPIO,             /* JP1: 0: LCD, 1: serial console */
        MPP46_GPIO,             /* External SATA HDD1 error indicator */
        MPP47_GPIO,             /* External SATA HDD2 error indicator */
        MPP48_GPIO,             /* External SATA HDD3 error indicator */
@@ -131,12 +134,14 @@ static void __init qnap_ts41x_init(void)
 
        pm_power_off = qnap_tsx1x_power_off;
 
+       if (gpio_request(QNAP_TS41X_JUMPER_JP1, "JP1") == 0)
+               gpio_export(QNAP_TS41X_JUMPER_JP1, 0);
 }
 
 static int __init ts41x_pci_init(void)
 {
        if (machine_is_ts41x())
-               kirkwood_pcie_init();
+               kirkwood_pcie_init(KW_PCIE0);
 
    return 0;
 }
index 78499667eb7b3241c3a5c1dfbbc69df4840a3991..5fcd082a17f9bff9b0d8a0818b199ebffd5833d2 100644 (file)
@@ -268,8 +268,8 @@ static void __init ks8695_pci_preinit(void)
        __raw_writel(0, KS8695_PCI_VA + KS8695_PIOBAC);
 
        /* hook in fault handlers */
-       hook_fault_code(8, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch");
-       hook_fault_code(10, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch");
+       hook_fault_code(8, ks8695_pci_fault, SIGBUS, 0, "external abort on non-linefetch");
+       hook_fault_code(10, ks8695_pci_fault, SIGBUS, 0, "external abort on non-linefetch");
 }
 
 static void ks8695_show_pciregs(void)
diff --git a/arch/arm/mach-l7200/Makefile b/arch/arm/mach-l7200/Makefile
deleted file mode 100644 (file)
index 4bd8ebd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y                  := core.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
-
diff --git a/arch/arm/mach-l7200/Makefile.boot b/arch/arm/mach-l7200/Makefile.boot
deleted file mode 100644 (file)
index 6c72ecb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-   zreladdr-y  := 0xf0008000
-
diff --git a/arch/arm/mach-l7200/core.c b/arch/arm/mach-l7200/core.c
deleted file mode 100644 (file)
index 50d2324..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *  linux/arch/arm/mm/mm-lusl7200.c
- *
- *  Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- *  Extra MM routines for L7200 architecture
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/device.h>
-
-#include <asm/types.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <asm/page.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-/*
- * IRQ base register
- */
-#define        IRQ_BASE        (IO_BASE_2 + 0x1000)
-
-/* 
- * Normal IRQ registers
- */
-#define IRQ_STATUS     (*(volatile unsigned long *) (IRQ_BASE + 0x000))
-#define IRQ_RAWSTATUS  (*(volatile unsigned long *) (IRQ_BASE + 0x004))
-#define IRQ_ENABLE     (*(volatile unsigned long *) (IRQ_BASE + 0x008))
-#define IRQ_ENABLECLEAR        (*(volatile unsigned long *) (IRQ_BASE + 0x00c))
-#define IRQ_SOFT       (*(volatile unsigned long *) (IRQ_BASE + 0x010))
-#define IRQ_SOURCESEL  (*(volatile unsigned long *) (IRQ_BASE + 0x018))
-
-/* 
- * Fast IRQ registers
- */
-#define FIQ_STATUS     (*(volatile unsigned long *) (IRQ_BASE + 0x100))
-#define FIQ_RAWSTATUS  (*(volatile unsigned long *) (IRQ_BASE + 0x104))
-#define FIQ_ENABLE     (*(volatile unsigned long *) (IRQ_BASE + 0x108))
-#define FIQ_ENABLECLEAR        (*(volatile unsigned long *) (IRQ_BASE + 0x10c))
-#define FIQ_SOFT       (*(volatile unsigned long *) (IRQ_BASE + 0x110))
-#define FIQ_SOURCESEL  (*(volatile unsigned long *) (IRQ_BASE + 0x118))
-
-static void l7200_mask_irq(unsigned int irq)
-{
-       IRQ_ENABLECLEAR = 1 << irq;
-}
-
-static void l7200_unmask_irq(unsigned int irq)
-{
-       IRQ_ENABLE = 1 << irq;
-}
-
-static struct irq_chip l7200_irq_chip = {
-       .ack            = l7200_mask_irq,
-       .mask           = l7200_mask_irq,
-       .unmask         = l7200_unmask_irq
-};
-static void __init l7200_init_irq(void)
-{
-       int irq;
-
-       IRQ_ENABLECLEAR = 0xffffffff;   /* clear all interrupt enables */
-       FIQ_ENABLECLEAR = 0xffffffff;   /* clear all fast interrupt enables */
-
-       for (irq = 0; irq < NR_IRQS; irq++) {
-               set_irq_chip(irq, &l7200_irq_chip);
-               set_irq_flags(irq, IRQF_VALID);
-               set_irq_handler(irq, handle_level_irq);
-       }
-
-       init_FIQ();
-}
-
-static struct map_desc l7200_io_desc[] __initdata = {
-       { IO_BASE,      IO_START,       IO_SIZE,        MT_DEVICE },
-       { IO_BASE_2,    IO_START_2,     IO_SIZE_2,      MT_DEVICE },
-       { AUX_BASE,     AUX_START,      AUX_SIZE,       MT_DEVICE },
-       { FLASH1_BASE,  FLASH1_START,   FLASH1_SIZE,    MT_DEVICE },
-       { FLASH2_BASE,  FLASH2_START,   FLASH2_SIZE,    MT_DEVICE }
-};
-
-static void __init l7200_map_io(void)
-{
-       iotable_init(l7200_io_desc, ARRAY_SIZE(l7200_io_desc));
-}
-
-MACHINE_START(L7200, "LinkUp Systems L7200")
-       /* Maintainer: Steve Hill / Scott McConnell */
-       .phys_io        = 0x80040000,
-       .io_pg_offst    = ((0xd0000000) >> 18) & 0xfffc,
-       .map_io         = l7200_map_io,
-       .init_irq       = l7200_init_irq,
-MACHINE_END
-
diff --git a/arch/arm/mach-l7200/include/mach/aux_reg.h b/arch/arm/mach-l7200/include/mach/aux_reg.h
deleted file mode 100644 (file)
index 4671558..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/aux_reg.h
- *
- * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *   08-02-2000        SJH     Created file
- */
-#ifndef _ASM_ARCH_AUXREG_H
-#define _ASM_ARCH_AUXREG_H
-
-#include <mach/hardware.h>
-
-#define l7200aux_reg   *((volatile unsigned int *) (AUX_BASE))
-
-/*
- * Auxillary register values
- */
-#define AUX_CLEAR              0x00000000
-#define AUX_DIAG_LED_ON                0x00000002
-#define AUX_RTS_UART1          0x00000004
-#define AUX_DTR_UART1          0x00000008
-#define AUX_KBD_COLUMN_12_HIGH 0x00000010
-#define AUX_KBD_COLUMN_12_OFF  0x00000020
-#define AUX_KBD_COLUMN_13_HIGH 0x00000040
-#define AUX_KBD_COLUMN_13_OFF  0x00000080
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/debug-macro.S b/arch/arm/mach-l7200/include/mach/debug-macro.S
deleted file mode 100644 (file)
index b69ed34..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* arch/arm/mach-l7200/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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.
- *
-*/
-
-               .equ    io_virt, IO_BASE
-               .equ    io_phys, IO_START
-
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #io_phys           @ physical base address
-               movne   \rx, #io_virt           @ virtual address
-               add     \rx, \rx, #0x00044000   @ UART1
-@              add     \rx, \rx, #0x00045000   @ UART2
-               .endm
-
-               .macro  senduart,rd,rx
-               str     \rd, [\rx, #0x0]        @ UARTDR
-               .endm
-
-               .macro  waituart,rd,rx
-1001:          ldr     \rd, [\rx, #0x18]       @ UARTFLG
-               tst     \rd, #1 << 5            @ UARTFLGUTXFF - 1 when full
-               bne     1001b
-               .endm
-
-               .macro  busyuart,rd,rx
-1001:          ldr     \rd, [\rx, #0x18]       @ UARTFLG
-               tst     \rd, #1 << 3            @ UARTFLGUBUSY - 1 when busy
-               bne     1001b
-               .endm
diff --git a/arch/arm/mach-l7200/include/mach/entry-macro.S b/arch/arm/mach-l7200/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 1726d91..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for L7200-based platforms
- *
- * 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 <mach/hardware.h>
-
-               .equ    irq_base_addr,  IO_BASE_2
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  get_irqnr_preamble, base, tmp
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
-               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-               mov     \irqstat, #irq_base_addr                @ Virt addr IRQ regs
-               add     \irqstat, \irqstat, #0x00001000         @ Status reg
-               ldr     \irqstat, [\irqstat, #0]                @ get interrupts
-               mov     \irqnr, #0
-1001:          tst     \irqstat, #1
-               addeq   \irqnr, \irqnr, #1
-               moveq   \irqstat, \irqstat, lsr #1
-               tsteq   \irqnr, #32
-               beq     1001b
-               teq     \irqnr, #32
-               .endm
-
diff --git a/arch/arm/mach-l7200/include/mach/gp_timers.h b/arch/arm/mach-l7200/include/mach/gp_timers.h
deleted file mode 100644 (file)
index 2b7086a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/gp_timers.h
- *
- * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *   07-28-2000        SJH     Created file
- *   08-02-2000        SJH     Used structure for registers
- */
-#ifndef _ASM_ARCH_GPTIMERS_H
-#define _ASM_ARCH_GPTIMERS_H
-
-#include <mach/hardware.h>
-
-/*
- * Layout of L7200 general purpose timer registers
- */
-struct GPT_Regs {
-       unsigned int TIMERLOAD;
-       unsigned int TIMERVALUE;
-       unsigned int TIMERCONTROL;
-       unsigned int TIMERCLEAR;
-};
-
-#define GPT_BASE               (IO_BASE_2 + 0x3000)
-#define l7200_timer1_regs      ((volatile struct GPT_Regs *) (GPT_BASE))
-#define l7200_timer2_regs      ((volatile struct GPT_Regs *) (GPT_BASE + 0x20))
-
-/*
- * General register values
- */
-#define        GPT_PRESCALE_1          0x00000000
-#define        GPT_PRESCALE_16         0x00000004
-#define        GPT_PRESCALE_256        0x00000008
-#define GPT_MODE_FREERUN       0x00000000
-#define GPT_MODE_PERIODIC      0x00000040
-#define GPT_ENABLE             0x00000080
-#define GPT_BZTOG              0x00000100
-#define GPT_BZMOD              0x00000200
-#define GPT_LOAD_MASK          0x0000ffff
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/gpio.h b/arch/arm/mach-l7200/include/mach/gpio.h
deleted file mode 100644 (file)
index c7b0a5d..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/****************************************************************************/
-/*
- *      arch/arm/mach-l7200/include/mach/gpio.h
- *
- *      Registers and  helper functions for the L7200 Link-Up Systems
- *      GPIO.
- *
- *      (C) Copyright 2000, S A McConnell  (samcconn@cotw.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.
- */
-
-/****************************************************************************/
-
-#define GPIO_OFF   0x00005000  /* Offset from IO_START to the GPIO reg's. */
-
-/* IO_START and IO_BASE are defined in hardware.h */
-
-#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */
-#define GPIO_BASE  (IO_BASE_2  + GPIO_OFF) /* Virtual addr of the GPIO reg. */
-
-/* Offsets from the start of the GPIO for all the registers. */
-#define PADR_OFF     0x000
-#define PADDR_OFF    0x004
-#define PASBSR_OFF   0x008
-#define PAEENR_OFF   0x00c
-#define PAESNR_OFF   0x010
-#define PAESTR_OFF   0x014
-#define PAIMR_OFF    0x018
-#define PAINT_OFF    0x01c
-
-#define PBDR_OFF     0x020
-#define PBDDR_OFF    0x024
-#define PBSBSR_OFF   0x028
-#define PBIMR_OFF    0x038
-#define PBINT_OFF    0x03c
-
-#define PCDR_OFF     0x040
-#define PCDDR_OFF    0x044
-#define PCSBSR_OFF   0x048
-#define PCIMR_OFF    0x058
-#define PCINT_OFF    0x05c
-
-#define PDDR_OFF     0x060
-#define PDDDR_OFF    0x064
-#define PDSBSR_OFF   0x068
-#define PDEENR_OFF   0x06c
-#define PDESNR_OFF   0x070
-#define PDESTR_OFF   0x074
-#define PDIMR_OFF    0x078
-#define PDINT_OFF    0x07c
-
-#define PEDR_OFF     0x080
-#define PEDDR_OFF    0x084
-#define PESBSR_OFF   0x088
-#define PEEENR_OFF   0x08c
-#define PEESNR_OFF   0x090
-#define PEESTR_OFF   0x094
-#define PEIMR_OFF    0x098
-#define PEINT_OFF    0x09c
-
-/* Define the GPIO registers for use by device drivers and the kernel. */
-#define PADR   (*(volatile unsigned long *)(GPIO_BASE+PADR_OFF))
-#define PADDR  (*(volatile unsigned long *)(GPIO_BASE+PADDR_OFF))
-#define PASBSR (*(volatile unsigned long *)(GPIO_BASE+PASBSR_OFF))
-#define PAEENR (*(volatile unsigned long *)(GPIO_BASE+PAEENR_OFF))
-#define PAESNR (*(volatile unsigned long *)(GPIO_BASE+PAESNR_OFF))
-#define PAESTR (*(volatile unsigned long *)(GPIO_BASE+PAESTR_OFF))
-#define PAIMR  (*(volatile unsigned long *)(GPIO_BASE+PAIMR_OFF))
-#define PAINT  (*(volatile unsigned long *)(GPIO_BASE+PAINT_OFF))
-
-#define PBDR   (*(volatile unsigned long *)(GPIO_BASE+PBDR_OFF))
-#define PBDDR  (*(volatile unsigned long *)(GPIO_BASE+PBDDR_OFF))
-#define PBSBSR (*(volatile unsigned long *)(GPIO_BASE+PBSBSR_OFF))
-#define PBIMR  (*(volatile unsigned long *)(GPIO_BASE+PBIMR_OFF))
-#define PBINT  (*(volatile unsigned long *)(GPIO_BASE+PBINT_OFF))
-
-#define PCDR   (*(volatile unsigned long *)(GPIO_BASE+PCDR_OFF))
-#define PCDDR  (*(volatile unsigned long *)(GPIO_BASE+PCDDR_OFF))
-#define PCSBSR (*(volatile unsigned long *)(GPIO_BASE+PCSBSR_OFF))
-#define PCIMR  (*(volatile unsigned long *)(GPIO_BASE+PCIMR_OFF))
-#define PCINT  (*(volatile unsigned long *)(GPIO_BASE+PCINT_OFF))
-
-#define PDDR   (*(volatile unsigned long *)(GPIO_BASE+PDDR_OFF))
-#define PDDDR  (*(volatile unsigned long *)(GPIO_BASE+PDDDR_OFF))
-#define PDSBSR (*(volatile unsigned long *)(GPIO_BASE+PDSBSR_OFF))
-#define PDEENR (*(volatile unsigned long *)(GPIO_BASE+PDEENR_OFF))
-#define PDESNR (*(volatile unsigned long *)(GPIO_BASE+PDESNR_OFF))
-#define PDESTR (*(volatile unsigned long *)(GPIO_BASE+PDESTR_OFF))
-#define PDIMR  (*(volatile unsigned long *)(GPIO_BASE+PDIMR_OFF))
-#define PDINT  (*(volatile unsigned long *)(GPIO_BASE+PDINT_OFF))
-
-#define PEDR   (*(volatile unsigned long *)(GPIO_BASE+PEDR_OFF))
-#define PEDDR  (*(volatile unsigned long *)(GPIO_BASE+PEDDR_OFF))
-#define PESBSR (*(volatile unsigned long *)(GPIO_BASE+PESBSR_OFF))
-#define PEEENR (*(volatile unsigned long *)(GPIO_BASE+PEEENR_OFF))
-#define PEESNR (*(volatile unsigned long *)(GPIO_BASE+PEESNR_OFF))
-#define PEESTR (*(volatile unsigned long *)(GPIO_BASE+PEESTR_OFF))
-#define PEIMR  (*(volatile unsigned long *)(GPIO_BASE+PEIMR_OFF))
-#define PEINT  (*(volatile unsigned long *)(GPIO_BASE+PEINT_OFF))
-
-#define VEE_EN         0x02
-#define BACKLIGHT_EN   0x04
diff --git a/arch/arm/mach-l7200/include/mach/hardware.h b/arch/arm/mach-l7200/include/mach/hardware.h
deleted file mode 100644 (file)
index c31909c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/hardware.h
- *
- * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
- *                    Steve Hill (sjhill@cotw.com)
- *
- * This file contains the hardware definitions for the 
- * LinkUp Systems L7200 SOC development board.
- *
- * Changelog:
- *   02-01-2000         RS     Created L7200 version, derived from rpc code
- *   03-21-2000        SJH     Cleaned up file
- *   04-21-2000         RS     Changed mapping of I/O in virtual space
- *   04-25-2000        SJH     Removed unused symbols and such
- *   05-05-2000        SJH     Complete rewrite
- *   07-31-2000        SJH     Added undocumented debug auxillary port to
- *                     get at last two columns for keyboard driver
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/* Hardware addresses of major areas.
- *  *_START is the physical address
- *  *_SIZE  is the size of the region
- *  *_BASE  is the virtual address
- */
-#define RAM_START              0xf0000000
-#define RAM_SIZE               0x02000000
-#define RAM_BASE               0xc0000000
-
-#define IO_START               0x80000000      /* I/O */
-#define IO_SIZE                        0x01000000
-#define IO_BASE                        0xd0000000
-
-#define IO_START_2             0x90000000      /* I/O */
-#define IO_SIZE_2              0x01000000
-#define IO_BASE_2              0xd1000000
-
-#define AUX_START              0x1a000000      /* AUX PORT */
-#define AUX_SIZE               0x01000000
-#define AUX_BASE               0xd2000000
-
-#define FLASH1_START           0x00000000      /* FLASH BANK 1 */
-#define FLASH1_SIZE            0x01000000
-#define FLASH1_BASE            0xd3000000
-
-#define FLASH2_START           0x10000000      /* FLASH BANK 2 */
-#define FLASH2_SIZE            0x01000000
-#define FLASH2_BASE            0xd4000000
-
-#define ISA_START              0x20000000      /* ISA */
-#define ISA_SIZE               0x20000000
-#define ISA_BASE               0xe0000000
-
-#define PCIO_BASE              IO_BASE
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/io.h b/arch/arm/mach-l7200/include/mach/io.h
deleted file mode 100644 (file)
index a770a89..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/io.h
- *
- * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *  03-21-2000 SJH     Created from arch/arm/mach-nexuspci/include/mach/io.h
- *  08-31-2000 SJH     Added in IO functions necessary for new drivers
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * There are not real ISA nor PCI buses, so we fake it.
- */
-#define __io(a)                __typesafe_io(a)
-#define __mem_pci(a)   (a)
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/irqs.h b/arch/arm/mach-l7200/include/mach/irqs.h
deleted file mode 100644 (file)
index 7edffd7..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/irqs.h
- *
- * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
- *                    Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *   01-02-2000 RS     Create l7200 version
- *   03-28-2000 SJH    Removed unused interrupt
- *   07-28-2000 SJH    Added pseudo-keyboard interrupt
- */
-
-/*
- * NOTE: The second timer (Timer 2) is used as the keyboard
- *       interrupt when the keyboard driver is enabled.
- */
-
-#define NR_IRQS          32
-
-#define IRQ_STWDOG        0   /* Watchdog timer */
-#define IRQ_PROG          1   /* Programmable interrupt */
-#define IRQ_DEBUG_RX      2   /* Comm Rx debug */
-#define IRQ_DEBUG_TX      3   /* Comm Tx debug */
-#define IRQ_GCTC1         4   /* Timer 1 */
-#define IRQ_GCTC2         5   /* Timer 2 / Keyboard */
-#define IRQ_DMA           6   /* DMA controller */
-#define IRQ_CLCD          7   /* Color LCD controller */
-#define IRQ_SM_RX         8   /* Smart card */
-#define IRQ_SM_TX         9   /* Smart cart */
-#define IRQ_SM_RST       10   /* Smart card */
-#define IRQ_SIB          11   /* Serial Interface Bus */
-#define IRQ_MMC          12   /* MultiMediaCard */
-#define IRQ_SSP1         13   /* Synchronous Serial Port 1 */
-#define IRQ_SSP2         14   /* Synchronous Serial Port 1 */
-#define IRQ_SPI          15   /* SPI slave */
-#define IRQ_UART_1       16   /* UART 1 */
-#define IRQ_UART_2       17   /* UART 2 */
-#define IRQ_IRDA         18   /* IRDA */
-#define IRQ_RTC_TICK     19   /* Real Time Clock tick */
-#define IRQ_RTC_ALARM    20   /* Real Time Clock alarm */
-#define IRQ_GPIO         21   /* General Purpose IO */
-#define IRQ_GPIO_DMA     22   /* General Purpose IO, DMA */
-#define IRQ_M2M          23   /* Memory to memory DMA  */
-#define IRQ_RESERVED     24   /* RESERVED, don't use */
-#define IRQ_INTF         25   /* External active low interrupt */
-#define IRQ_INT0         26   /* External active low interrupt */
-#define IRQ_INT1         27   /* External active low interrupt */
-#define IRQ_INT2         28   /* External active low interrupt */
-#define IRQ_UCB1200      29   /* Interrupt generated by UCB1200*/
-#define IRQ_BAT_LO       30   /* Low batery or external power */
-#define IRQ_MEDIA_CHG    31   /* Media change interrupt */
-
-/*
- * This is the offset of the FIQ "IRQ" numbers
- */
-#define FIQ_START      64
diff --git a/arch/arm/mach-l7200/include/mach/memory.h b/arch/arm/mach-l7200/include/mach/memory.h
deleted file mode 100644 (file)
index 9fb40ed..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/memory.h
- *
- * Copyright (c) 2000 Steve Hill (sjhill@cotw.com)
- * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net)
- *
- * Changelog:
- *  03-13-2000 SJH     Created
- *  04-13-2000  RS      Changed bus macros for new addr
- *  05-03-2000  SJH     Removed bus macros and fixed virt_to_phys macro
- */
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-/*
- * Physical DRAM offset on the L7200 SDB.
- */
-#define PHYS_OFFSET     UL(0xf0000000)
-
-/*
- * Cache flushing area - ROM
- */
-#define FLUSH_BASE_PHYS                0x40000000
-#define FLUSH_BASE             0xdf000000
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/pmpcon.h b/arch/arm/mach-l7200/include/mach/pmpcon.h
deleted file mode 100644 (file)
index 3959871..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/****************************************************************************/
-/*
- *  arch/arm/mach-l7200/include/mach/pmpcon.h
- *
- *   Registers and  helper functions for the L7200 Link-Up Systems
- *   DC/DC converter register.
- *
- *   (C) Copyright 2000, S A McConnell  (samcconn@cotw.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.
- */
-
-/****************************************************************************/
-
-#define PMPCON_OFF 0x00006000  /* Offset from IO_START_2. */
-
-/* IO_START_2 and IO_BASE_2 are defined in hardware.h */
-
-#define PMPCON_START (IO_START_2 + PMPCON_OFF)  /* Physical address of reg. */
-#define PMPCON_BASE  (IO_BASE_2  + PMPCON_OFF)  /* Virtual address of reg. */
-
-
-#define PMPCON (*(volatile unsigned int *)(PMPCON_BASE))
-
-#define PWM2_50CYCLE 0x800
-#define CONTRAST     0x9
-
-#define PWM1H (CONTRAST)
-#define PWM1L (CONTRAST << 4)
-
-#define PMPCON_VALUE  (PWM2_50CYCLE | PWM1L | PWM1H) 
-       
-/* PMPCON = 0x811;   // too light and fuzzy
- * PMPCON = 0x844;   
- * PMPCON = 0x866;   // better color poor depth
- * PMPCON = 0x888;   // Darker but better depth 
- * PMPCON = 0x899;   // Darker even better depth
- * PMPCON = 0x8aa;   // too dark even better depth
- * PMPCON = 0X8cc;   // Way too dark
- */
-
-/* As CONTRAST value increases the greater the depth perception and
- * the darker the colors.
- */
diff --git a/arch/arm/mach-l7200/include/mach/pmu.h b/arch/arm/mach-l7200/include/mach/pmu.h
deleted file mode 100644 (file)
index a2da7ae..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************/
-/*
- *  arch/arm/mach-l7200/include/mach/pmu.h
- *
- *   Registers and  helper functions for the L7200 Link-Up Systems
- *   Power Management Unit (PMU).
- *
- *   (C) Copyright 2000, S A McConnell  (samcconn@cotw.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.
- */
-
-/****************************************************************************/
-
-#define PMU_OFF   0x00050000  /* Offset from IO_START to the PMU registers. */
-
-/* IO_START and IO_BASE are defined in hardware.h */
-
-#define PMU_START (IO_START + PMU_OFF)  /* Physical addr. of the PMU reg. */
-#define PMU_BASE  (IO_BASE  + PMU_OFF)  /* Virtual addr. of the PMU reg. */
-
-
-/* Define the PMU registers for use by device drivers and the kernel. */
-
-typedef struct {
-     unsigned int CURRENT;  /* Current configuration register */
-     unsigned int NEXT;     /* Next configuration register */
-     unsigned int reserved;
-     unsigned int RUN;      /* Run configuration register */
-     unsigned int COMM;     /* Configuration command register */
-     unsigned int SDRAM;    /* SDRAM configuration bypass register */
-} pmu_interface;
-
-#define PMU ((volatile pmu_interface *)(PMU_BASE))
-
-
-/* Macro's for reading the common register fields. */
-
-#define GET_TRANSOP(reg)  ((reg >> 25) & 0x03) /* Bits 26-25 */
-#define GET_OSCEN(reg)    ((reg >> 16) & 0x01)
-#define GET_OSCMUX(reg)   ((reg >> 15) & 0x01)
-#define GET_PLLMUL(reg)   ((reg >>  9) & 0x3f) /* Bits 14-9 */
-#define GET_PLLEN(reg)    ((reg >>  8) & 0x01)
-#define GET_PLLMUX(reg)   ((reg >>  7) & 0x01)
-#define GET_BCLK_DIV(reg) ((reg >>  3) & 0x03) /* Bits 4-3 */
-#define GET_SDRB_SEL(reg) ((reg >>  2) & 0x01)
-#define GET_SDRF_SEL(reg) ((reg >>  1) & 0x01)
-#define GET_FASTBUS(reg)  (reg & 0x1)
-
-/* CFG_NEXT register */
-
-#define CFG_NEXT_CLOCKRECOVERY ((PMU->NEXT >> 18) & 0x7f)   /* Bits 24-18 */
-#define CFG_NEXT_INTRET        ((PMU->NEXT >> 17) & 0x01)
-#define CFG_NEXT_SDR_STOP      ((PMU->NEXT >>  6) & 0x01)
-#define CFG_NEXT_SYSCLKEN      ((PMU->NEXT >>  5) & 0x01)
-
-/* Useful field values that can be used to construct the
- * CFG_NEXT and CFG_RUN registers.
- */
-
-#define TRANSOP_NOP      0<<25  /* NOCHANGE_NOSTALL */
-#define NOCHANGE_STALL   1<<25
-#define CHANGE_NOSTALL   2<<25
-#define CHANGE_STALL     3<<25
-
-#define INTRET           1<<17
-#define OSCEN            1<<16
-#define OSCMUX           1<<15
-
-/* PLL frequencies */
-
-#define PLLMUL_0         0<<9         /*  3.6864 MHz */
-#define PLLMUL_1         1<<9         /*  ?????? MHz */
-#define PLLMUL_5         5<<9         /*  18.432 MHz */
-#define PLLMUL_10       10<<9         /*  36.864 MHz */
-#define PLLMUL_18       18<<9         /*  ?????? MHz */
-#define PLLMUL_20       20<<9         /*  73.728 MHz */
-#define PLLMUL_32       32<<9         /*  ?????? MHz */
-#define PLLMUL_35       35<<9         /* 129.024 MHz */
-#define PLLMUL_36       36<<9         /*  ?????? MHz */
-#define PLLMUL_39       39<<9         /*  ?????? MHz */
-#define PLLMUL_40       40<<9         /* 147.456 MHz */
-
-/* Clock recovery times */
-
-#define CRCLOCK_1        1<<18
-#define CRCLOCK_2        2<<18
-#define CRCLOCK_4        4<<18
-#define CRCLOCK_8        8<<18
-#define CRCLOCK_16      16<<18
-#define CRCLOCK_32      32<<18
-#define CRCLOCK_63      63<<18
-#define CRCLOCK_127    127<<18
-
-#define PLLEN            1<<8
-#define PLLMUX           1<<7
-#define SDR_STOP         1<<6
-#define SYSCLKEN         1<<5
-
-#define BCLK_DIV_4       2<<3
-#define BCLK_DIV_2       1<<3
-#define BCLK_DIV_1       0<<3
-
-#define SDRB_SEL         1<<2
-#define SDRF_SEL         1<<1
-#define FASTBUS          1<<0
-
-
-/* CFG_SDRAM */
-
-#define SDRREFFQ         1<<0  /* Only if SDRSTOPRQ is not set. */
-#define SDRREFACK        1<<1  /* Read-only */
-#define SDRSTOPRQ        1<<2  /* Only if SDRREFFQ is not set. */
-#define SDRSTOPACK       1<<3  /* Read-only */
-#define PICEN            1<<4  /* Enable Co-procesor */
-#define PICTEST          1<<5
-
-#define GET_SDRREFFQ    ((PMU->SDRAM >> 0) & 0x01)
-#define GET_SDRREFACK   ((PMU->SDRAM >> 1) & 0x01) /* Read-only */
-#define GET_SDRSTOPRQ   ((PMU->SDRAM >> 2) & 0x01)
-#define GET_SDRSTOPACK  ((PMU->SDRAM >> 3) & 0x01) /* Read-only */
-#define GET_PICEN       ((PMU->SDRAM >> 4) & 0x01)
-#define GET_PICTEST     ((PMU->SDRAM >> 5) & 0x01)
diff --git a/arch/arm/mach-l7200/include/mach/serial.h b/arch/arm/mach-l7200/include/mach/serial.h
deleted file mode 100644 (file)
index adc05e5..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/serial.h
- *
- * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net)
- *                    Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *  03-20-2000  SJH     Created
- *  03-26-2000  SJH     Added flags for serial ports
- *  03-27-2000  SJH     Corrected BASE_BAUD value
- *  04-14-2000  RS      Made register addr dependent on IO_BASE
- *  05-03-2000  SJH     Complete rewrite
- *  05-09-2000 SJH     Stripped out architecture specific serial stuff
- *                      and placed it in a separate file
- *  07-28-2000 SJH     Moved base baud rate variable
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 3.6864 MHz clock for your UART.
- */
-#define BASE_BAUD      3686400
-
-/*
- * Standard COM flags
- */
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-#define STD_SERIAL_PORT_DEFNS          \
-       /* MAGIC UART CLK   PORT       IRQ     FLAGS */                 \
-       { 0, BASE_BAUD, UART1_BASE, IRQ_UART_1, STD_COM_FLAGS },  /* ttyLU0 */ \
-       { 0, BASE_BAUD, UART2_BASE, IRQ_UART_2, STD_COM_FLAGS },  /* ttyLU1 */ \
-
-#define EXTRA_SERIAL_PORT_DEFNS
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/serial_l7200.h b/arch/arm/mach-l7200/include/mach/serial_l7200.h
deleted file mode 100644 (file)
index 645f1c5..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/serial_l7200.h
- *
- * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
- *
- * Changelog:
- *  05-09-2000 SJH     Created
- */
-#ifndef __ASM_ARCH_SERIAL_L7200_H
-#define __ASM_ARCH_SERIAL_L7200_H
-
-#include <mach/memory.h>
-
-/*
- * This assumes you have a 3.6864 MHz clock for your UART.
- */
-#define BASE_BAUD 3686400
-
-/*
- * UART base register addresses
- */
-#define UART1_BASE     (IO_BASE + 0x00044000)
-#define UART2_BASE     (IO_BASE + 0x00045000)
-
-/*
- * UART register offsets
- */
-#define UARTDR                 0x00    /* Tx/Rx data */
-#define RXSTAT                 0x04    /* Rx status */
-#define H_UBRLCR               0x08    /* mode register high */
-#define M_UBRLCR               0x0C    /* mode reg mid (MSB of baud)*/
-#define L_UBRLCR               0x10    /* mode reg low (LSB of baud)*/
-#define UARTCON                        0x14    /* control register */
-#define UARTFLG                        0x18    /* flag register */
-#define UARTINTSTAT            0x1C    /* FIFO IRQ status register */
-#define UARTINTMASK            0x20    /* FIFO IRQ mask register */
-
-/*
- * UART baud rate register values
- */
-#define BR_110                 0x827
-#define BR_1200                        0x06e
-#define BR_2400                        0x05f
-#define BR_4800                        0x02f
-#define BR_9600                        0x017
-#define BR_14400               0x00f
-#define BR_19200               0x00b
-#define BR_38400               0x005
-#define BR_57600               0x003
-#define BR_76800               0x002
-#define BR_115200              0x001
-
-/*
- * Receiver status register (RXSTAT) mask values
- */
-#define RXSTAT_NO_ERR          0x00    /* No error */
-#define RXSTAT_FRM_ERR         0x01    /* Framing error */
-#define RXSTAT_PAR_ERR         0x02    /* Parity error */
-#define RXSTAT_OVR_ERR         0x04    /* Overrun error */
-
-/*
- * High byte of UART bit rate and line control register (H_UBRLCR) values
- */
-#define UBRLCR_BRK             0x01    /* generate break on tx */
-#define UBRLCR_PEN             0x02    /* enable parity */
-#define UBRLCR_PDIS            0x00    /* disable parity */
-#define UBRLCR_EVEN            0x04    /* 1= even parity,0 = odd parity */
-#define UBRLCR_STP2            0x08    /* transmit 2 stop bits */
-#define UBRLCR_FIFO            0x10    /* enable FIFO */
-#define UBRLCR_LEN5            0x60    /* word length5 */
-#define UBRLCR_LEN6            0x40    /* word length6 */
-#define UBRLCR_LEN7            0x20    /* word length7 */
-#define UBRLCR_LEN8            0x00    /* word length8 */
-
-/*
- * UART control register (UARTCON) values
- */
-#define UARTCON_UARTEN         0x01    /* Enable UART */
-#define UARTCON_DMAONERR       0x08    /* Mask RxDmaRq when errors occur */
-
-/*
- * UART flag register (UARTFLG) mask values
- */
-#define UARTFLG_UTXFF          0x20    /* Transmit FIFO full */
-#define UARTFLG_URXFE          0x10    /* Receiver FIFO empty */
-#define UARTFLG_UBUSY          0x08    /* Transmitter busy */
-#define UARTFLG_DCD            0x04    /* Data carrier detect */
-#define UARTFLG_DSR            0x02    /* Data set ready */
-#define UARTFLG_CTS            0x01    /* Clear to send */
-
-/*
- * UART interrupt status/clear registers (UARTINTSTAT/CLR) values
- */
-#define UART_TXINT             0x01    /* TX interrupt */
-#define UART_RXINT             0x02    /* RX interrupt */
-#define UART_RXERRINT          0x04    /* RX error interrupt */
-#define UART_MSINT             0x08    /* Modem Status interrupt */
-#define UART_UDINT             0x10    /* UART Disabled interrupt */
-#define UART_ALLIRQS           0x1f    /* All interrupts */
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/sib.h b/arch/arm/mach-l7200/include/mach/sib.h
deleted file mode 100644 (file)
index 9657287..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************************/
-/*
- *  arch/arm/mach-l7200/include/mach/sib.h
- *
- *  Registers and helper functions for the Serial Interface Bus.
- *
- *  (C) Copyright 2000, S A McConnell  (samcconn@cotw.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.
- */
-
-/****************************************************************************/
-
-#define SIB_OFF   0x00040000  /* Offset from IO_START to the SIB reg's. */
-
-/* IO_START and IO_BASE are defined in hardware.h */
-
-#define SIB_START (IO_START + SIB_OFF) /* Physical addr of the SIB reg. */
-#define SIB_BASE  (IO_BASE  + SIB_OFF) /* Virtual addr of the SIB reg.  */
-
-/* Offsets from the start of the SIB for all the registers. */
-
-/* Define the SIB registers for use by device drivers and the kernel. */
-
-typedef struct
-{
-     unsigned int MCCR;    /* SIB Control Register           Offset: 0x00 */
-     unsigned int RES1;    /* Reserved                       Offset: 0x04 */
-     unsigned int MCDR0;   /* SIB Data Register 0            Offset: 0x08 */
-     unsigned int MCDR1;   /* SIB Data Register 1            Offset: 0x0c */
-     unsigned int MCDR2;   /* SIB Data Register 2 (UCB1x00)  Offset: 0x10 */
-     unsigned int RES2;    /* Reserved                       Offset: 0x14 */
-     unsigned int MCSR;    /* SIB Status Register            Offset: 0x18 */
-} SIB_Interface;
-
-#define SIB ((volatile SIB_Interface *) (SIB_BASE))
-
-/* MCCR */
-
-#define INTERNAL_FREQ   9216000  /* Hertz */
-#define AUDIO_FREQ         5000  /* Hertz */
-#define TELECOM_FREQ       5000  /* Hertz */
-
-#define AUDIO_DIVIDE    (INTERNAL_FREQ / (32 * AUDIO_FREQ))
-#define TELECOM_DIVIDE  (INTERNAL_FREQ / (32 * TELECOM_FREQ))
-
-#define MCCR_ASD57      AUDIO_DIVIDE
-#define MCCR_TSD57      (TELECOM_DIVIDE << 8)
-#define MCCR_MCE        (1 << 16)             /* SIB enable */
-#define MCCR_ECS        (1 << 17)             /* External Clock Select */
-#define MCCR_ADM        (1 << 18)             /* A/D Data Sampling */
-#define MCCR_PMC        (1 << 26)             /* PIN Multiplexer Control */
-
-
-#define GET_ASD ((SIB->MCCR >>  0) & 0x3f) /* Audio Sample Rate Div. */
-#define GET_TSD ((SIB->MCCR >>  8) & 0x3f) /* Telcom Sample Rate Div. */
-#define GET_MCE ((SIB->MCCR >> 16) & 0x01) /* SIB Enable */
-#define GET_ECS ((SIB->MCCR >> 17) & 0x01) /* External Clock Select */
-#define GET_ADM ((SIB->MCCR >> 18) & 0x01) /* A/D Data Sampling Mode */
-#define GET_TTM ((SIB->MCCR >> 19) & 0x01) /* Telco Trans. FIFO I mask */ 
-#define GET_TRM ((SIB->MCCR >> 20) & 0x01) /* Telco Recv. FIFO I mask */
-#define GET_ATM ((SIB->MCCR >> 21) & 0x01) /* Audio Trans. FIFO I mask */ 
-#define GET_ARM ((SIB->MCCR >> 22) & 0x01) /* Audio Recv. FIFO I mask */
-#define GET_LBM ((SIB->MCCR >> 23) & 0x01) /* Loop Back Mode */
-#define GET_ECP ((SIB->MCCR >> 24) & 0x03) /* Extern. Clck Prescale sel */
-#define GET_PMC ((SIB->MCCR >> 26) & 0x01) /* PIN Multiplexer Control */
-#define GET_ERI ((SIB->MCCR >> 27) & 0x01) /* External Read Interrupt */
-#define GET_EWI ((SIB->MCCR >> 28) & 0x01) /* External Write Interrupt */
-
-/* MCDR0 */
-
-#define AUDIO_RECV     ((SIB->MCDR0 >> 4) & 0xfff)
-#define AUDIO_WRITE(v) ((SIB->MCDR0 = (v & 0xfff) << 4))
-
-/* MCDR1 */
-
-#define TELECOM_RECV     ((SIB->MCDR1 >> 2) & 032fff)
-#define TELECOM_WRITE(v) ((SIB->MCDR1 = (v & 0x3fff) << 2))
-
-
-/* MCSR */
-
-#define MCSR_ATU (1 << 4)  /* Audio Transmit FIFO Underrun */
-#define MCSR_ARO (1 << 5)  /* Audio Receive  FIFO Underrun */
-#define MCSR_TTU (1 << 6)  /* TELECOM Transmit FIFO Underrun */
-#define MCSR_TRO (1 << 7)  /* TELECOM Receive  FIFO Underrun */
-
-#define MCSR_CLEAR_UNDERUN_BITS (MCSR_ATU | MCSR_ARO | MCSR_TTU | MCSR_TRO)
-
-
-#define GET_ATS ((SIB->MCSR >>  0) & 0x01) /* Audio Transmit FIFO Service Req*/
-#define GET_ARS ((SIB->MCSR >>  1) & 0x01) /* Audio Recv FIFO Service Request*/
-#define GET_TTS ((SIB->MCSR >>  2) & 0x01) /* TELECOM Transmit FIFO  Flag */
-#define GET_TRS ((SIB->MCSR >>  3) & 0x01) /* TELECOM Recv FIFO Service Req. */
-#define GET_ATU ((SIB->MCSR >>  4) & 0x01) /* Audio Transmit FIFO Underrun */
-#define GET_ARO ((SIB->MCSR >>  5) & 0x01) /* Audio Receive  FIFO Underrun */
-#define GET_TTU ((SIB->MCSR >>  6) & 0x01) /* TELECOM Transmit FIFO Underrun */
-#define GET_TRO ((SIB->MCSR >>  7) & 0x01) /* TELECOM Receive  FIFO Underrun */
-#define GET_ANF ((SIB->MCSR >>  8) & 0x01) /* Audio Transmit FIFO not full */
-#define GET_ANE ((SIB->MCSR >>  9) & 0x01) /* Audio Receive FIFO not empty */
-#define GET_TNF ((SIB->MCSR >> 10) & 0x01) /* Telecom Transmit FIFO not full */
-#define GET_TNE ((SIB->MCSR >> 11) & 0x01) /* Telecom Receive FIFO not empty */
-#define GET_CWC ((SIB->MCSR >> 12) & 0x01) /* Codec Write Complete */
-#define GET_CRC ((SIB->MCSR >> 13) & 0x01) /* Codec Read Complete */
-#define GET_ACE ((SIB->MCSR >> 14) & 0x01) /* Audio Codec Enabled */
-#define GET_TCE ((SIB->MCSR >> 15) & 0x01) /* Telecom Codec Enabled */
-
-/* MCDR2 */
-
-#define MCDR2_rW               (1 << 16)
-
-#define WRITE_MCDR2(reg, data) (SIB->MCDR2 =((reg<<17)|MCDR2_rW|(data&0xffff)))
-#define MCDR2_WRITE_COMPLETE   GET_CWC
-
-#define INITIATE_MCDR2_READ(reg) (SIB->MCDR2 = (reg << 17))
-#define MCDR2_READ_COMPLETE      GET_CRC
-#define MCDR2_READ               (SIB->MCDR2 & 0xffff)
diff --git a/arch/arm/mach-l7200/include/mach/sys-clock.h b/arch/arm/mach-l7200/include/mach/sys-clock.h
deleted file mode 100644 (file)
index e9729a3..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************/
-/*
- *  arch/arm/mach-l7200/include/mach/sys-clock.h
- *
- *   Registers and  helper functions for the L7200 Link-Up Systems
- *   System clocks.
- *
- *   (C) Copyright 2000, S A McConnell  (samcconn@cotw.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.
- */
-
-/****************************************************************************/
-
-#define SYS_CLOCK_OFF   0x00050030  /* Offset from IO_START. */
-
-/* IO_START and IO_BASE are defined in hardware.h */
-
-#define SYS_CLOCK_START (IO_START + SYS_CLOCK_OFF)  /* Physical address */
-#define SYS_CLOCK_BASE  (IO_BASE  + SYS_CLOCK_OFF)  /* Virtual address  */
-
-/* Define the interface to the SYS_CLOCK */
-
-typedef struct
-{
-     unsigned int ENABLE;
-     unsigned int ESYNC;
-     unsigned int SELECT;
-} sys_clock_interface;
-
-#define SYS_CLOCK   ((volatile sys_clock_interface *)(SYS_CLOCK_BASE))
-
-//#define CLOCK_EN    (*(volatile unsigned long *)(PMU_BASE+CLOCK_EN_OFF))
-//#define CLOCK_ESYNC (*(volatile unsigned long *)(PMU_BASE+CLOCK_ESYNC_OFF))
-//#define CLOCK_SEL   (*(volatile unsigned long *)(PMU_BASE+CLOCK_SEL_OFF))
-
-/* SYS_CLOCK -> ENABLE */
-
-#define SYN_EN          1<<0
-#define B18M_EN         1<<1
-#define CLK3M6_EN       1<<2
-#define BUART_EN        1<<3
-#define CLK18MU_EN      1<<4
-#define FIR_EN          1<<5
-#define MIRN_EN         1<<6
-#define UARTM_EN        1<<7
-#define SIBADC_EN       1<<8
-#define ALTD_EN         1<<9
-#define CLCLK_EN        1<<10
-
-/* SYS_CLOCK -> SELECT */
-
-#define CLK18M_DIV      1<<0
-#define MIR_SEL         1<<1
-#define SSP_SEL         1<<4
-#define MM_DIV          1<<5
-#define MM_SEL          1<<6
-#define ADC_SEL_2       0<<7
-#define ADC_SEL_4       1<<7
-#define ADC_SEL_8       3<<7
-#define ADC_SEL_16      7<<7
-#define ADC_SEL_32      0x0f<<7
-#define ADC_SEL_64      0x1f<<7
-#define ADC_SEL_128     0x3f<<7
-#define ALTD_SEL        1<<13
diff --git a/arch/arm/mach-l7200/include/mach/system.h b/arch/arm/mach-l7200/include/mach/system.h
deleted file mode 100644 (file)
index e0dd3b6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/system.h
- *
- * Copyright (c) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog
- *  03-21-2000  SJH    Created
- *  04-26-2000  SJH    Fixed functions
- *  05-03-2000  SJH    Removed usage of obsolete 'iomd.h'
- *  05-31-2000  SJH    Properly implemented 'arch_idle'
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <mach/hardware.h>
-
-static inline void arch_idle(void)
-{
-       *(unsigned long *)(IO_BASE + 0x50004) = 1;      /* idle mode */
-}
-
-static inline void arch_reset(char mode, const char *cmd)
-{
-       if (mode == 's') {
-               cpu_reset(0);
-       }
-}
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/time.h b/arch/arm/mach-l7200/include/mach/time.h
deleted file mode 100644 (file)
index 061771c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/time.h
- *
- * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
- *                    Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *   01-02-2000        RS      Created l7200 version, derived from rpc code
- *   05-03-2000        SJH     Complete rewrite
- */
-#ifndef _ASM_ARCH_TIME_H
-#define _ASM_ARCH_TIME_H
-
-#include <mach/irqs.h>
-
-/*
- * RTC base register address
- */
-#define RTC_BASE       (IO_BASE_2 + 0x2000)
-
-/*
- * RTC registers
- */
-#define RTC_RTCDR      (*(volatile unsigned char *) (RTC_BASE + 0x000))
-#define RTC_RTCMR      (*(volatile unsigned char *) (RTC_BASE + 0x004))
-#define RTC_RTCS       (*(volatile unsigned char *) (RTC_BASE + 0x008))
-#define RTC_RTCC       (*(volatile unsigned char *) (RTC_BASE + 0x008))
-#define RTC_RTCDV      (*(volatile unsigned char *) (RTC_BASE + 0x00c))
-#define RTC_RTCCR      (*(volatile unsigned char *) (RTC_BASE + 0x010))
-
-/*
- * RTCCR register values
- */
-#define RTC_RATE_32    0x00      /* 32 Hz tick */
-#define RTC_RATE_64    0x10      /* 64 Hz tick */
-#define RTC_RATE_128   0x20      /* 128 Hz tick */
-#define RTC_RATE_256   0x30      /* 256 Hz tick */
-#define RTC_EN_ALARM   0x01      /* Enable alarm */
-#define RTC_EN_TIC     0x04      /* Enable counter */
-#define RTC_EN_STWDOG  0x08      /* Enable watchdog */
-
-/*
- * Handler for RTC timer interrupt
- */
-static irqreturn_t
-timer_interrupt(int irq, void *dev_id)
-{
-       struct pt_regs *regs = get_irq_regs();
-       do_timer(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(regs));
-#endif
-       do_profile(regs);
-       RTC_RTCC = 0;                           /* Clear interrupt */
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Set up RTC timer interrupt, and return the current time in seconds.
- */
-void __init time_init(void)
-{
-       RTC_RTCC = 0;                           /* Clear interrupt */
-
-       timer_irq.handler = timer_interrupt;
-
-       setup_irq(IRQ_RTC_TICK, &timer_irq);
-
-       RTC_RTCCR = RTC_RATE_128 | RTC_EN_TIC;  /* Set rate and enable timer */
-}
-
-#endif
diff --git a/arch/arm/mach-l7200/include/mach/timex.h b/arch/arm/mach-l7200/include/mach/timex.h
deleted file mode 100644 (file)
index ffc96a6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/timex.h
- *
- * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
- *                    Steve Hill (sjhill@cotw.com)
- *
- * 04-21-2000  RS Created file
- * 05-03-2000 SJH Tick rate was wrong
- *
- */
-
-/*
- * On the ARM720T, clock ticks are set to 128 Hz.
- *
- * NOTE: The actual RTC value is set in 'time.h' which
- *       must be changed when choosing a different tick
- *       rate. The value of HZ in 'param.h' must also
- *       be changed to match below.
- */
-#define CLOCK_TICK_RATE                128
diff --git a/arch/arm/mach-l7200/include/mach/uncompress.h b/arch/arm/mach-l7200/include/mach/uncompress.h
deleted file mode 100644 (file)
index 591c962..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/uncompress.h
- *
- * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *  05-01-2000 SJH     Created
- *  05-13-2000 SJH     Filled in function bodies
- *  07-26-2000 SJH     Removed hard coded baud rate
- */
-
-#include <mach/hardware.h>
-
-#define IO_UART  IO_START + 0x00044000
-
-#define __raw_writeb(v,p)      (*(volatile unsigned char *)(p) = (v))
-#define __raw_readb(p)         (*(volatile unsigned char *)(p))
-
-static inline void putc(int c)
-{
-       while(__raw_readb(IO_UART + 0x18) & 0x20 ||
-             __raw_readb(IO_UART + 0x18) & 0x08)
-               barrier();
-
-       __raw_writeb(c, IO_UART + 0x00);
-}
-
-static inline void flush(void)
-{
-}
-
-static __inline__ void arch_decomp_setup(void)
-{
-       __raw_writeb(0x00, IO_UART + 0x08);     /* Set HSB */
-       __raw_writeb(0x00, IO_UART + 0x20);     /* Disable IRQs */
-       __raw_writeb(0x01, IO_UART + 0x14);     /* Enable UART */
-}
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-l7200/include/mach/vmalloc.h b/arch/arm/mach-l7200/include/mach/vmalloc.h
deleted file mode 100644 (file)
index 85f0abb..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/vmalloc.h
- */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
index 189d20e543e75f41b52a39f4f009e30ed87ed2d5..edb8f5faf5d5032c9047d4c743a66e1230dbe0e8 100644 (file)
  */
 #define PHYS_OFFSET    UL(0xc0000000)
 
-#ifdef CONFIG_DISCONTIGMEM
-
-/*
- * Given a kernel address, find the home node of the underlying memory.
- */
-
-# ifdef CONFIG_LH7A40X_ONE_BANK_PER_NODE
-#  define KVADDR_TO_NID(addr) \
-  (  ((((unsigned long) (addr) - PAGE_OFFSET) >> 24) &  1)\
-   | ((((unsigned long) (addr) - PAGE_OFFSET) >> 25) & ~1))
-# else  /* 2 banks per node */
-#  define KVADDR_TO_NID(addr) \
-      (((unsigned long) (addr) - PAGE_OFFSET) >> 26)
-# endif
-
-/*
- * Given a page frame number, convert it to a node id.
- */
-
-# ifdef CONFIG_LH7A40X_ONE_BANK_PER_NODE
-#  define PFN_TO_NID(pfn) \
-  (((((pfn) - PHYS_PFN_OFFSET) >> (24 - PAGE_SHIFT)) &  1)\
- | ((((pfn) - PHYS_PFN_OFFSET) >> (25 - PAGE_SHIFT)) & ~1))
-# else  /* 2 banks per node */
-#  define PFN_TO_NID(pfn) \
-    (((pfn) - PHYS_PFN_OFFSET) >> (26 - PAGE_SHIFT))
-#endif
-
-/*
- * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory
- * and returns the index corresponding to the appropriate page in the
- * node's mem_map.
- */
-
-# ifdef CONFIG_LH7A40X_ONE_BANK_PER_NODE
-#  define LOCAL_MAP_NR(addr) \
-       (((unsigned long)(addr) & 0x003fffff) >> PAGE_SHIFT)
-# else  /* 2 banks per node */
-#  define LOCAL_MAP_NR(addr) \
-       (((unsigned long)(addr) & 0x01ffffff) >> PAGE_SHIFT)
-# endif
-
-#endif
-
 /*
  * Sparsemem version of the above
  */
diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
new file mode 100644 (file)
index 0000000..fde6635
--- /dev/null
@@ -0,0 +1,33 @@
+if ARCH_LPC32XX
+
+menu "Individual UART enable selections"
+
+config ARCH_LPC32XX_UART3_SELECT
+       bool "Add support for standard UART3"
+       help
+        Adds support for standard UART 3 when the 8250 serial support
+        is enabled.
+
+config ARCH_LPC32XX_UART4_SELECT
+       bool "Add support for standard UART4"
+       help
+        Adds support for standard UART 4 when the 8250 serial support
+        is enabled.
+
+config ARCH_LPC32XX_UART5_SELECT
+       bool "Add support for standard UART5"
+       default y
+       help
+        Adds support for standard UART 5 when the 8250 serial support
+        is enabled.
+
+config ARCH_LPC32XX_UART6_SELECT
+       bool "Add support for standard UART6"
+       help
+        Adds support for standard UART 6 when the 8250 serial support
+        is enabled.
+
+endmenu
+
+endif
+
diff --git a/arch/arm/mach-lpc32xx/Makefile b/arch/arm/mach-lpc32xx/Makefile
new file mode 100644 (file)
index 0000000..a5fc5d0
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y  := timer.o irq.o common.o serial.o clock.o
+obj-y  += gpiolib.o pm.o suspend.o
+obj-y  += phy3250.o
+
diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
new file mode 100644 (file)
index 0000000..b796b41
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x80008000
+params_phys-y  := 0x80000100
+initrd_phys-y  := 0x82000000
+
diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
new file mode 100644 (file)
index 0000000..32d6379
--- /dev/null
@@ -0,0 +1,1137 @@
+/*
+ * arch/arm/mach-lpc32xx/clock.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+/*
+ * LPC32xx clock management driver overview
+ *
+ * The LPC32XX contains a number of high level system clocks that can be
+ * generated from different sources. These system clocks are used to
+ * generate the CPU and bus rates and the individual peripheral clocks in
+ * the system. When Linux is started by the boot loader, the system
+ * clocks are already running. Stopping a system clock during normal
+ * Linux operation should never be attempted, as peripherals that require
+ * those clocks will quit working (ie, DRAM).
+ *
+ * The LPC32xx high level clock tree looks as follows. Clocks marked with
+ * an asterisk are always on and cannot be disabled. Clocks marked with
+ * an ampersand can only be disabled in CPU suspend mode. Clocks marked
+ * with a caret are always on if it is the selected clock for the SYSCLK
+ * source. The clock that isn't used for SYSCLK can be enabled and
+ * disabled normally.
+ *                               32KHz oscillator*
+ *                               /      |      \
+ *                             RTC*   PLL397^ TOUCH
+ *                                     /
+ *               Main oscillator^     /
+ *                   |        \      /
+ *                   |         SYSCLK&
+ *                   |            \
+ *                   |             \
+ *                USB_PLL       HCLK_PLL&
+ *                   |           |    |
+ *            USB host/device  PCLK&  |
+ *                               |    |
+ *                             Peripherals
+ *
+ * The CPU and chip bus rates are derived from the HCLK PLL, which can
+ * generate various clock rates up to 266MHz and beyond. The internal bus
+ * rates (PCLK and HCLK) are generated from dividers based on the HCLK
+ * PLL rate. HCLK can be a ratio of 1:1, 1:2, or 1:4 or HCLK PLL rate,
+ * while PCLK can be 1:1 to 1:32 of HCLK PLL rate. Most peripherals high
+ * level clocks are based on either HCLK or PCLK, but have their own
+ * dividers as part of the IP itself. Because of this, the system clock
+ * rates should not be changed.
+ *
+ * The HCLK PLL is clocked from SYSCLK, which can be derived from the
+ * main oscillator or PLL397. PLL397 generates a rate that is 397 times
+ * the 32KHz oscillator rate. The main oscillator runs at the selected
+ * oscillator/crystal rate on the mosc_in pin of the LPC32xx. This rate
+ * is normally 13MHz, but depends on the selection of external crystals
+ * or oscillators. If USB operation is required, the main oscillator must
+ * be used in the system.
+ *
+ * Switching SYSCLK between sources during normal Linux operation is not
+ * supported. SYSCLK is preset in the bootloader. Because of the
+ * complexities of clock management during clock frequency changes,
+ * there are some limitations to the clock driver explained below:
+ * - The PLL397 and main oscillator can be enabled and disabled by the
+ *   clk_enable() and clk_disable() functions unless SYSCLK is based
+ *   on that clock. This allows the other oscillator that isn't driving
+ *   the HCLK PLL to be used as another system clock that can be routed
+ *   to an external pin.
+ * - The muxed SYSCLK input and HCLK_PLL rate cannot be changed with
+ *   this driver.
+ * - HCLK and PCLK rates cannot be changed as part of this driver.
+ * - Most peripherals have their own dividers are part of the peripheral
+ *   block. Changing SYSCLK, HCLK PLL, HCLK, or PCLK sources or rates
+ *   will also impact the individual peripheral rates.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+
+#include <mach/hardware.h>
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
+#include <mach/platform.h>
+#include "clock.h"
+#include "common.h"
+
+static struct clk clk_armpll;
+static struct clk clk_usbpll;
+static DEFINE_MUTEX(clkm_lock);
+
+/*
+ * Post divider values for PLLs based on selected register value
+ */
+static const u32 pll_postdivs[4] = {1, 2, 4, 8};
+
+static unsigned long local_return_parent_rate(struct clk *clk)
+{
+       /*
+        * If a clock has a rate of 0, then it inherits it's parent
+        * clock rate
+        */
+       while (clk->rate == 0)
+               clk = clk->parent;
+
+       return clk->rate;
+}
+
+/* 32KHz clock has a fixed rate and is not stoppable */
+static struct clk osc_32KHz = {
+       .rate           = LPC32XX_CLOCK_OSC_FREQ,
+       .get_rate       = local_return_parent_rate,
+};
+
+static int local_pll397_enable(struct clk *clk, int enable)
+{
+       u32 reg;
+       unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+       reg = __raw_readl(LPC32XX_CLKPWR_PLL397_CTRL);
+
+       if (enable == 0) {
+               reg |= LPC32XX_CLKPWR_SYSCTRL_PLL397_DIS;
+               __raw_writel(reg, LPC32XX_CLKPWR_PLL397_CTRL);
+       } else {
+               /* Enable PLL397 */
+               reg &= ~LPC32XX_CLKPWR_SYSCTRL_PLL397_DIS;
+               __raw_writel(reg, LPC32XX_CLKPWR_PLL397_CTRL);
+
+               /* Wait for PLL397 lock */
+               while (((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
+                       LPC32XX_CLKPWR_SYSCTRL_PLL397_STS) == 0) &&
+                       (timeout > jiffies))
+                       cpu_relax();
+
+               if ((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
+                       LPC32XX_CLKPWR_SYSCTRL_PLL397_STS) == 0)
+                       return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int local_oscmain_enable(struct clk *clk, int enable)
+{
+       u32 reg;
+       unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+       reg = __raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL);
+
+       if (enable == 0) {
+               reg |= LPC32XX_CLKPWR_MOSC_DISABLE;
+               __raw_writel(reg, LPC32XX_CLKPWR_MAIN_OSC_CTRL);
+       } else {
+               /* Enable main oscillator */
+               reg &= ~LPC32XX_CLKPWR_MOSC_DISABLE;
+               __raw_writel(reg, LPC32XX_CLKPWR_MAIN_OSC_CTRL);
+
+               /* Wait for main oscillator to start */
+               while (((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
+                       LPC32XX_CLKPWR_MOSC_DISABLE) != 0) &&
+                       (timeout > jiffies))
+                       cpu_relax();
+
+               if ((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
+                       LPC32XX_CLKPWR_MOSC_DISABLE) != 0)
+                       return -ENODEV;
+       }
+
+       return 0;
+}
+
+static struct clk osc_pll397 = {
+       .parent         = &osc_32KHz,
+       .enable         = local_pll397_enable,
+       .rate           = LPC32XX_CLOCK_OSC_FREQ * 397,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk osc_main = {
+       .enable         = local_oscmain_enable,
+       .rate           = LPC32XX_MAIN_OSC_FREQ,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_sys;
+
+/*
+ * Convert a PLL register value to a PLL output frequency
+ */
+u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval)
+{
+       struct clk_pll_setup pllcfg;
+
+       pllcfg.cco_bypass_b15 = 0;
+       pllcfg.direct_output_b14 = 0;
+       pllcfg.fdbk_div_ctrl_b13 = 0;
+       if ((regval & LPC32XX_CLKPWR_HCLKPLL_CCO_BYPASS) != 0)
+               pllcfg.cco_bypass_b15 = 1;
+       if ((regval & LPC32XX_CLKPWR_HCLKPLL_POSTDIV_BYPASS) != 0)
+               pllcfg.direct_output_b14 = 1;
+       if ((regval & LPC32XX_CLKPWR_HCLKPLL_FDBK_SEL_FCLK) != 0)
+               pllcfg.fdbk_div_ctrl_b13 = 1;
+       pllcfg.pll_m = 1 + ((regval >> 1) & 0xFF);
+       pllcfg.pll_n = 1 + ((regval >> 9) & 0x3);
+       pllcfg.pll_p = pll_postdivs[((regval >> 11) & 0x3)];
+
+       return clk_check_pll_setup(inputclk, &pllcfg);
+}
+
+/*
+ * Setup the HCLK PLL with a PLL structure
+ */
+static u32 local_clk_pll_setup(struct clk_pll_setup *PllSetup)
+{
+       u32 tv, tmp = 0;
+
+       if (PllSetup->analog_on != 0)
+               tmp |= LPC32XX_CLKPWR_HCLKPLL_POWER_UP;
+       if (PllSetup->cco_bypass_b15 != 0)
+               tmp |= LPC32XX_CLKPWR_HCLKPLL_CCO_BYPASS;
+       if (PllSetup->direct_output_b14 != 0)
+               tmp |= LPC32XX_CLKPWR_HCLKPLL_POSTDIV_BYPASS;
+       if (PllSetup->fdbk_div_ctrl_b13 != 0)
+               tmp |= LPC32XX_CLKPWR_HCLKPLL_FDBK_SEL_FCLK;
+
+       tv = ffs(PllSetup->pll_p) - 1;
+       if ((!is_power_of_2(PllSetup->pll_p)) || (tv > 3))
+               return 0;
+
+       tmp |= LPC32XX_CLKPWR_HCLKPLL_POSTDIV_2POW(tv);
+       tmp |= LPC32XX_CLKPWR_HCLKPLL_PREDIV_PLUS1(PllSetup->pll_n - 1);
+       tmp |= LPC32XX_CLKPWR_HCLKPLL_PLLM(PllSetup->pll_m - 1);
+
+       return tmp;
+}
+
+/*
+ * Update the ARM core PLL frequency rate variable from the actual PLL setting
+ */
+static void local_update_armpll_rate(void)
+{
+       u32 clkin, pllreg;
+
+       clkin = clk_armpll.parent->rate;
+       pllreg = __raw_readl(LPC32XX_CLKPWR_HCLKPLL_CTRL) & 0x1FFFF;
+
+       clk_armpll.rate = clk_get_pllrate_from_reg(clkin, pllreg);
+}
+
+/*
+ * Find a PLL configuration for the selected input frequency
+ */
+static u32 local_clk_find_pll_cfg(u32 pllin_freq, u32 target_freq,
+       struct clk_pll_setup *pllsetup)
+{
+       u32 ifreq, freqtol, m, n, p, fclkout;
+
+       /* Determine frequency tolerance limits */
+       freqtol = target_freq / 250;
+       ifreq = pllin_freq;
+
+       /* Is direct bypass mode possible? */
+       if (abs(pllin_freq - target_freq) <= freqtol) {
+               pllsetup->analog_on = 0;
+               pllsetup->cco_bypass_b15 = 1;
+               pllsetup->direct_output_b14 = 1;
+               pllsetup->fdbk_div_ctrl_b13 = 1;
+               pllsetup->pll_p = pll_postdivs[0];
+               pllsetup->pll_n = 1;
+               pllsetup->pll_m = 1;
+               return clk_check_pll_setup(ifreq, pllsetup);
+       } else if (target_freq <= ifreq) {
+               pllsetup->analog_on = 0;
+               pllsetup->cco_bypass_b15 = 1;
+               pllsetup->direct_output_b14 = 0;
+               pllsetup->fdbk_div_ctrl_b13 = 1;
+               pllsetup->pll_n = 1;
+               pllsetup->pll_m = 1;
+               for (p = 0; p <= 3; p++) {
+                       pllsetup->pll_p = pll_postdivs[p];
+                       fclkout = clk_check_pll_setup(ifreq, pllsetup);
+                       if (abs(target_freq - fclkout) <= freqtol)
+                               return fclkout;
+               }
+       }
+
+       /* Is direct mode possible? */
+       pllsetup->analog_on = 1;
+       pllsetup->cco_bypass_b15 = 0;
+       pllsetup->direct_output_b14 = 1;
+       pllsetup->fdbk_div_ctrl_b13 = 0;
+       pllsetup->pll_p = pll_postdivs[0];
+       for (m = 1; m <= 256; m++) {
+               for (n = 1; n <= 4; n++) {
+                       /* Compute output frequency for this value */
+                       pllsetup->pll_n = n;
+                       pllsetup->pll_m = m;
+                       fclkout = clk_check_pll_setup(ifreq,
+                               pllsetup);
+                       if (abs(target_freq - fclkout) <=
+                               freqtol)
+                               return fclkout;
+               }
+       }
+
+       /* Is integer mode possible? */
+       pllsetup->analog_on = 1;
+       pllsetup->cco_bypass_b15 = 0;
+       pllsetup->direct_output_b14 = 0;
+       pllsetup->fdbk_div_ctrl_b13 = 1;
+       for (m = 1; m <= 256; m++) {
+               for (n = 1; n <= 4; n++) {
+                       for (p = 0; p < 4; p++) {
+                               /* Compute output frequency */
+                               pllsetup->pll_p = pll_postdivs[p];
+                               pllsetup->pll_n = n;
+                               pllsetup->pll_m = m;
+                               fclkout = clk_check_pll_setup(
+                                       ifreq, pllsetup);
+                               if (abs(target_freq - fclkout) <= freqtol)
+                                       return fclkout;
+                       }
+               }
+       }
+
+       /* Try non-integer mode */
+       pllsetup->analog_on = 1;
+       pllsetup->cco_bypass_b15 = 0;
+       pllsetup->direct_output_b14 = 0;
+       pllsetup->fdbk_div_ctrl_b13 = 0;
+       for (m = 1; m <= 256; m++) {
+               for (n = 1; n <= 4; n++) {
+                       for (p = 0; p < 4; p++) {
+                               /* Compute output frequency */
+                               pllsetup->pll_p = pll_postdivs[p];
+                               pllsetup->pll_n = n;
+                               pllsetup->pll_m = m;
+                               fclkout = clk_check_pll_setup(
+                                       ifreq, pllsetup);
+                               if (abs(target_freq - fclkout) <= freqtol)
+                                       return fclkout;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static struct clk clk_armpll = {
+       .parent         = &clk_sys,
+       .get_rate       = local_return_parent_rate,
+};
+
+/*
+ * Setup the USB PLL with a PLL structure
+ */
+static u32 local_clk_usbpll_setup(struct clk_pll_setup *pHCLKPllSetup)
+{
+       u32 reg, tmp = local_clk_pll_setup(pHCLKPllSetup);
+
+       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL) & ~0x1FFFF;
+       reg |= tmp;
+       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+       return clk_check_pll_setup(clk_usbpll.parent->rate,
+               pHCLKPllSetup);
+}
+
+static int local_usbpll_enable(struct clk *clk, int enable)
+{
+       u32 reg;
+       int ret = -ENODEV;
+       unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+
+       if (enable == 0) {
+               reg &= ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
+                       LPC32XX_CLKPWR_USBCTRL_CLK_EN2);
+               __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+       } else if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP) {
+               reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
+               __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+               /* Wait for PLL lock */
+               while ((timeout > jiffies) & (ret == -ENODEV)) {
+                       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+                       if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_STS)
+                               ret = 0;
+               }
+
+               if (ret == 0) {
+                       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
+                       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+               }
+       }
+
+       return ret;
+}
+
+static unsigned long local_usbpll_round_rate(struct clk *clk,
+       unsigned long rate)
+{
+       u32 clkin, usbdiv;
+       struct clk_pll_setup pllsetup;
+
+       /*
+        * Unlike other clocks, this clock has a KHz input rate, so bump
+        * it up to work with the PLL function
+        */
+       rate = rate * 1000;
+
+       clkin = clk->parent->rate;
+       usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
+               LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
+       clkin = clkin / usbdiv;
+
+       /* Try to find a good rate setup */
+       if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
+               return 0;
+
+       return clk_check_pll_setup(clkin, &pllsetup);
+}
+
+static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 clkin, reg, usbdiv;
+       struct clk_pll_setup pllsetup;
+
+       /*
+        * Unlike other clocks, this clock has a KHz input rate, so bump
+        * it up to work with the PLL function
+        */
+       rate = rate * 1000;
+
+       clkin = clk->get_rate(clk);
+       usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
+               LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
+       clkin = clkin / usbdiv;
+
+       /* Try to find a good rate setup */
+       if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
+               return -EINVAL;
+
+       local_usbpll_enable(clk, 0);
+
+       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
+       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+       pllsetup.analog_on = 1;
+       local_clk_usbpll_setup(&pllsetup);
+
+       clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+
+       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
+       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+       return 0;
+}
+
+static struct clk clk_usbpll = {
+       .parent         = &osc_main,
+       .set_rate       = local_usbpll_set_rate,
+       .enable         = local_usbpll_enable,
+       .rate           = 48000, /* In KHz */
+       .get_rate       = local_return_parent_rate,
+       .round_rate     = local_usbpll_round_rate,
+};
+
+static u32 clk_get_hclk_div(void)
+{
+       static const u32 hclkdivs[4] = {1, 2, 4, 4};
+       return hclkdivs[LPC32XX_CLKPWR_HCLKDIV_DIV_2POW(
+               __raw_readl(LPC32XX_CLKPWR_HCLK_DIV))];
+}
+
+static struct clk clk_hclk = {
+       .parent         = &clk_armpll,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_pclk = {
+       .parent         = &clk_armpll,
+       .get_rate       = local_return_parent_rate,
+};
+
+static int local_onoff_enable(struct clk *clk, int enable)
+{
+       u32 tmp;
+
+       tmp = __raw_readl(clk->enable_reg);
+
+       if (enable == 0)
+               tmp &= ~clk->enable_mask;
+       else
+               tmp |= clk->enable_mask;
+
+       __raw_writel(tmp, clk->enable_reg);
+
+       return 0;
+}
+
+/* Peripheral clock sources */
+static struct clk clk_timer0 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+       .enable_mask    = LPC32XX_CLKPWR_TMRPWMCLK_TIMER0_EN,
+       .get_rate       = local_return_parent_rate,
+};
+static struct clk clk_timer1 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+       .enable_mask    = LPC32XX_CLKPWR_TMRPWMCLK_TIMER1_EN,
+       .get_rate       = local_return_parent_rate,
+};
+static struct clk clk_timer2 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+       .enable_mask    = LPC32XX_CLKPWR_TMRPWMCLK_TIMER2_EN,
+       .get_rate       = local_return_parent_rate,
+};
+static struct clk clk_timer3 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+       .enable_mask    = LPC32XX_CLKPWR_TMRPWMCLK_TIMER3_EN,
+       .get_rate       = local_return_parent_rate,
+};
+static struct clk clk_wdt = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_TIMER_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
+       .get_rate       = local_return_parent_rate,
+};
+static struct clk clk_vfp9 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_DEBUG_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_VFP_CLOCK_ENABLE_BIT,
+       .get_rate       = local_return_parent_rate,
+};
+static struct clk clk_dma = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_DMA_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_uart3 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_UART_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_UARTCLKCTRL_UART3_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_uart4 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_UART_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_UARTCLKCTRL_UART4_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_uart5 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_UART_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_UARTCLKCTRL_UART5_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_uart6 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_UART_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_UARTCLKCTRL_UART6_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_i2c0 = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_I2C_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_I2CCLK_I2C1CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_i2c1 = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_I2C_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_I2CCLK_I2C2CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_i2c2 = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = io_p2v(LPC32XX_USB_BASE + 0xFF4),
+       .enable_mask    = 0x4,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_ssp0 = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_SSP_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_ssp1 = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_SSP_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_SSPCTRL_SSPCLK1_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_kscan = {
+       .parent         = &osc_32KHz,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_KEY_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_KEYCLKCTRL_CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_nand = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_NAND_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_NANDCLK_SLCCLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_i2s0 = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_I2S_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_I2SCTRL_I2SCLK0_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_i2s1 = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_I2S_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_I2SCTRL_I2SCLK1_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_net = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_MACCLK_CTRL,
+       .enable_mask    = (LPC32XX_CLKPWR_MACCTRL_DMACLK_EN |
+               LPC32XX_CLKPWR_MACCTRL_MMIOCLK_EN |
+               LPC32XX_CLKPWR_MACCTRL_HRCCLK_EN),
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_rtc = {
+       .parent         = &osc_32KHz,
+       .rate           = 1, /* 1 Hz */
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_usbd = {
+       .parent         = &clk_usbpll,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_USB_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_USBCTRL_HCLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static int tsc_onoff_enable(struct clk *clk, int enable)
+{
+       u32 tmp;
+
+       /* Make sure 32KHz clock is the selected clock */
+       tmp = __raw_readl(LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+       tmp &= ~LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL;
+       __raw_writel(tmp, LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+
+       if (enable == 0)
+               __raw_writel(0, clk->enable_reg);
+       else
+               __raw_writel(clk->enable_mask, clk->enable_reg);
+
+       return 0;
+}
+
+static struct clk clk_tsc = {
+       .parent         = &osc_32KHz,
+       .enable         = tsc_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_ADC_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
+static int mmc_onoff_enable(struct clk *clk, int enable)
+{
+       u32 tmp;
+
+       tmp = __raw_readl(LPC32XX_CLKPWR_MS_CTRL) &
+               ~LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
+
+       /* If rate is 0, disable clock */
+       if (enable != 0)
+               tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
+
+       __raw_writel(tmp, LPC32XX_CLKPWR_MS_CTRL);
+
+       return 0;
+}
+
+static unsigned long mmc_get_rate(struct clk *clk)
+{
+       u32 div, rate, oldclk;
+
+       /* The MMC clock must be on when accessing an MMC register */
+       oldclk = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
+       __raw_writel(oldclk | LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
+               LPC32XX_CLKPWR_MS_CTRL);
+       div = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
+       __raw_writel(oldclk, LPC32XX_CLKPWR_MS_CTRL);
+
+       /* Get the parent clock rate */
+       rate = clk->parent->get_rate(clk->parent);
+
+       /* Get the MMC controller clock divider value */
+       div = div & LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(0xf);
+
+       if (!div)
+               div = 1;
+
+       return rate / div;
+}
+
+static unsigned long mmc_round_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long div, prate;
+
+       /* Get the parent clock rate */
+       prate = clk->parent->get_rate(clk->parent);
+
+       if (rate >= prate)
+               return prate;
+
+       div = prate / rate;
+       if (div > 0xf)
+               div = 0xf;
+
+       return prate / div;
+}
+
+static int mmc_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 oldclk, tmp;
+       unsigned long prate, div, crate = mmc_round_rate(clk, rate);
+
+       prate = clk->parent->get_rate(clk->parent);
+
+       div = prate / crate;
+
+       /* The MMC clock must be on when accessing an MMC register */
+       oldclk = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
+       __raw_writel(oldclk | LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
+               LPC32XX_CLKPWR_MS_CTRL);
+       tmp = __raw_readl(LPC32XX_CLKPWR_MS_CTRL) &
+               ~LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(0xf);
+       tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(div);
+       __raw_writel(tmp, LPC32XX_CLKPWR_MS_CTRL);
+
+       __raw_writel(oldclk, LPC32XX_CLKPWR_MS_CTRL);
+
+       return 0;
+}
+
+static struct clk clk_mmc = {
+       .parent         = &clk_armpll,
+       .set_rate       = mmc_set_rate,
+       .get_rate       = mmc_get_rate,
+       .round_rate     = mmc_round_rate,
+       .enable         = mmc_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_MS_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
+};
+
+static unsigned long clcd_get_rate(struct clk *clk)
+{
+       u32 tmp, div, rate, oldclk;
+
+       /* The LCD clock must be on when accessing an LCD register */
+       oldclk = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
+       __raw_writel(oldclk | LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
+               LPC32XX_CLKPWR_LCDCLK_CTRL);
+       tmp = __raw_readl(io_p2v(LPC32XX_LCD_BASE + CLCD_TIM2));
+       __raw_writel(oldclk, LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+       rate = clk->parent->get_rate(clk->parent);
+
+       /* Only supports internal clocking */
+       if (tmp & TIM2_BCD)
+               return rate;
+
+       div = (tmp & 0x1F) | ((tmp & 0xF8) >> 22);
+       tmp = rate / (2 + div);
+
+       return tmp;
+}
+
+static int clcd_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 tmp, prate, div, oldclk;
+
+       /* The LCD clock must be on when accessing an LCD register */
+       oldclk = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
+       __raw_writel(oldclk | LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
+               LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+       tmp = __raw_readl(io_p2v(LPC32XX_LCD_BASE + CLCD_TIM2)) | TIM2_BCD;
+       prate = clk->parent->get_rate(clk->parent);
+
+       if (rate < prate) {
+               /* Find closest divider */
+               div = prate / rate;
+               if (div >= 2) {
+                       div -= 2;
+                       tmp &= ~TIM2_BCD;
+               }
+
+               tmp &= ~(0xF800001F);
+               tmp |= (div & 0x1F);
+               tmp |= (((div >> 5) & 0x1F) << 27);
+       }
+
+       __raw_writel(tmp, io_p2v(LPC32XX_LCD_BASE + CLCD_TIM2));
+       __raw_writel(oldclk, LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+       return 0;
+}
+
+static unsigned long clcd_round_rate(struct clk *clk, unsigned long rate)
+{
+       u32 prate, div;
+
+       prate = clk->parent->get_rate(clk->parent);
+
+       if (rate >= prate)
+               rate = prate;
+       else {
+               div = prate / rate;
+               if (div > 0x3ff)
+                       div = 0x3ff;
+
+               rate = prate / div;
+       }
+
+       return rate;
+}
+
+static struct clk clk_lcd = {
+       .parent         = &clk_hclk,
+       .set_rate       = clcd_set_rate,
+       .get_rate       = clcd_get_rate,
+       .round_rate     = clcd_round_rate,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_LCDCLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
+};
+
+static inline void clk_lock(void)
+{
+       mutex_lock(&clkm_lock);
+}
+
+static inline void clk_unlock(void)
+{
+       mutex_unlock(&clkm_lock);
+}
+
+static void local_clk_disable(struct clk *clk)
+{
+       WARN_ON(clk->usecount == 0);
+
+       /* Don't attempt to disable clock if it has no users */
+       if (clk->usecount > 0) {
+               clk->usecount--;
+
+               /* Only disable clock when it has no more users */
+               if ((clk->usecount == 0) && (clk->enable))
+                       clk->enable(clk, 0);
+
+               /* Check parent clocks, they may need to be disabled too */
+               if (clk->parent)
+                       local_clk_disable(clk->parent);
+       }
+}
+
+static int local_clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       /* Enable parent clocks first and update use counts */
+       if (clk->parent)
+               ret = local_clk_enable(clk->parent);
+
+       if (!ret) {
+               /* Only enable clock if it's currently disabled */
+               if ((clk->usecount == 0) && (clk->enable))
+                       ret = clk->enable(clk, 1);
+
+               if (!ret)
+                       clk->usecount++;
+               else if (clk->parent)
+                       local_clk_disable(clk->parent);
+       }
+
+       return ret;
+}
+
+/*
+ * clk_enable - inform the system when the clock source should be running.
+ */
+int clk_enable(struct clk *clk)
+{
+       int ret;
+
+       clk_lock();
+       ret = local_clk_enable(clk);
+       clk_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+/*
+ * clk_disable - inform the system when the clock source is no longer required
+ */
+void clk_disable(struct clk *clk)
+{
+       clk_lock();
+       local_clk_disable(clk);
+       clk_unlock();
+}
+EXPORT_SYMBOL(clk_disable);
+
+/*
+ * clk_get_rate - obtain the current clock rate (in Hz) for a clock source
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+       unsigned long rate;
+
+       clk_lock();
+       rate = clk->get_rate(clk);
+       clk_unlock();
+
+       return rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*
+ * clk_set_rate - set the clock rate for a clock source
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+
+       /*
+        * Most system clocks can only be enabled or disabled, with
+        * the actual rate set as part of the peripheral dividers
+        * instead of high level clock control
+        */
+       if (clk->set_rate) {
+               clk_lock();
+               ret = clk->set_rate(clk, rate);
+               clk_unlock();
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * clk_round_rate - adjust a rate to the exact rate a clock can provide
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       clk_lock();
+
+       if (clk->round_rate)
+               rate = clk->round_rate(clk, rate);
+       else
+               rate = clk->get_rate(clk);
+
+       clk_unlock();
+
+       return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+/*
+ * clk_set_parent - set the parent clock source for this clock
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       /* Clock re-parenting is not supported */
+       return -EINVAL;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+/*
+ * clk_get_parent - get the parent clock source for this clock
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+       return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+#define _REGISTER_CLOCK(d, n, c) \
+       { \
+               .dev_id = (d), \
+               .con_id = (n), \
+               .clk = &(c), \
+       },
+
+static struct clk_lookup lookups[] = {
+       _REGISTER_CLOCK(NULL, "osc_32KHz", osc_32KHz)
+       _REGISTER_CLOCK(NULL, "osc_pll397", osc_pll397)
+       _REGISTER_CLOCK(NULL, "osc_main", osc_main)
+       _REGISTER_CLOCK(NULL, "sys_ck", clk_sys)
+       _REGISTER_CLOCK(NULL, "arm_pll_ck", clk_armpll)
+       _REGISTER_CLOCK(NULL, "ck_pll5", clk_usbpll)
+       _REGISTER_CLOCK(NULL, "hclk_ck", clk_hclk)
+       _REGISTER_CLOCK(NULL, "pclk_ck", clk_pclk)
+       _REGISTER_CLOCK(NULL, "timer0_ck", clk_timer0)
+       _REGISTER_CLOCK(NULL, "timer1_ck", clk_timer1)
+       _REGISTER_CLOCK(NULL, "timer2_ck", clk_timer2)
+       _REGISTER_CLOCK(NULL, "timer3_ck", clk_timer3)
+       _REGISTER_CLOCK(NULL, "vfp9_ck", clk_vfp9)
+       _REGISTER_CLOCK(NULL, "clk_dmac", clk_dma)
+       _REGISTER_CLOCK("pnx4008-watchdog", NULL, clk_wdt)
+       _REGISTER_CLOCK(NULL, "uart3_ck", clk_uart3)
+       _REGISTER_CLOCK(NULL, "uart4_ck", clk_uart4)
+       _REGISTER_CLOCK(NULL, "uart5_ck", clk_uart5)
+       _REGISTER_CLOCK(NULL, "uart6_ck", clk_uart6)
+       _REGISTER_CLOCK("pnx-i2c.0", NULL, clk_i2c0)
+       _REGISTER_CLOCK("pnx-i2c.1", NULL, clk_i2c1)
+       _REGISTER_CLOCK("pnx-i2c.2", NULL, clk_i2c2)
+       _REGISTER_CLOCK("dev:ssp0", NULL, clk_ssp0)
+       _REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
+       _REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
+       _REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
+       _REGISTER_CLOCK("tbd", "i2s0_ck", clk_i2s0)
+       _REGISTER_CLOCK("tbd", "i2s1_ck", clk_i2s1)
+       _REGISTER_CLOCK("lpc32xx-ts", NULL, clk_tsc)
+       _REGISTER_CLOCK("dev:mmc0", "MCLK", clk_mmc)
+       _REGISTER_CLOCK("lpc-net.0", NULL, clk_net)
+       _REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
+       _REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
+       _REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
+};
+
+static int __init clk_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
+
+       /*
+        * Setup muxed SYSCLK for HCLK PLL base -this selects the
+        * parent clock used for the ARM PLL and is used to derive
+        * the many system clock rates in the device.
+        */
+       if (clk_is_sysclk_mainosc() != 0)
+               clk_sys.parent = &osc_main;
+       else
+               clk_sys.parent = &osc_pll397;
+
+       clk_sys.rate = clk_sys.parent->rate;
+
+       /* Compute the current ARM PLL and USB PLL frequencies */
+       local_update_armpll_rate();
+
+       /* Compute HCLK and PCLK bus rates */
+       clk_hclk.rate = clk_hclk.parent->rate / clk_get_hclk_div();
+       clk_pclk.rate = clk_pclk.parent->rate / clk_get_pclk_div();
+
+       /*
+        * Enable system clocks - this step is somewhat formal, as the
+        * clocks are already running, but it does get the clock data
+        * inline with the actual system state. Never disable these
+        * clocks as they will only stop if the system is going to sleep.
+        * In that case, the chip/system power management functions will
+        * handle clock gating.
+        */
+       if (clk_enable(&clk_hclk) || clk_enable(&clk_pclk))
+               printk(KERN_ERR "Error enabling system HCLK and PCLK\n");
+
+       /*
+        * Timers 0 and 1 were enabled and are being used by the high
+        * resolution tick function prior to this driver being initialized.
+        * Tag them now as used.
+        */
+       if (clk_enable(&clk_timer0) || clk_enable(&clk_timer1))
+               printk(KERN_ERR "Error enabling timer tick clocks\n");
+
+       return 0;
+}
+core_initcall(clk_init);
+
diff --git a/arch/arm/mach-lpc32xx/clock.h b/arch/arm/mach-lpc32xx/clock.h
new file mode 100644 (file)
index 0000000..c0a8434
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/mach-lpc32xx/clock.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __LPC32XX_CLOCK_H
+#define __LPC32XX_CLOCK_H
+
+struct clk {
+       struct list_head node;
+       struct clk *parent;
+       u32 rate;
+       u32 usecount;
+
+       int (*set_rate) (struct clk *, unsigned long);
+       unsigned long (*round_rate) (struct clk *, unsigned long);
+       unsigned long (*get_rate) (struct clk *clk);
+       int (*enable) (struct clk *, int);
+
+       /* Register address and bit mask for simple clocks */
+       void __iomem *enable_reg;
+       u32 enable_mask;
+};
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
new file mode 100644 (file)
index 0000000..ee24dc2
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * arch/arm/mach-lpc32xx/common.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/i2c-pnx.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/i2c.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+/*
+ * Watchdog timer
+ */
+static struct resource watchdog_resources[] = {
+       [0] = {
+               .start = LPC32XX_WDTIM_BASE,
+               .end = LPC32XX_WDTIM_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device lpc32xx_watchdog_device = {
+       .name = "pnx4008-watchdog",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(watchdog_resources),
+       .resource = watchdog_resources,
+};
+
+/*
+ * I2C busses
+ */
+static struct i2c_pnx_data i2c0_data = {
+       .name = I2C_CHIP_NAME "1",
+       .base = LPC32XX_I2C1_BASE,
+       .irq = IRQ_LPC32XX_I2C_1,
+};
+
+static struct i2c_pnx_data i2c1_data = {
+       .name = I2C_CHIP_NAME "2",
+       .base = LPC32XX_I2C2_BASE,
+       .irq = IRQ_LPC32XX_I2C_2,
+};
+
+static struct i2c_pnx_data i2c2_data = {
+       .name = "USB-I2C",
+       .base = LPC32XX_OTG_I2C_BASE,
+       .irq = IRQ_LPC32XX_USB_I2C,
+};
+
+struct platform_device lpc32xx_i2c0_device = {
+       .name = "pnx-i2c",
+       .id = 0,
+       .dev = {
+               .platform_data = &i2c0_data,
+       },
+};
+
+struct platform_device lpc32xx_i2c1_device = {
+       .name = "pnx-i2c",
+       .id = 1,
+       .dev = {
+               .platform_data = &i2c1_data,
+       },
+};
+
+struct platform_device lpc32xx_i2c2_device = {
+       .name = "pnx-i2c",
+       .id = 2,
+       .dev = {
+               .platform_data = &i2c2_data,
+       },
+};
+
+/*
+ * Returns the unique ID for the device
+ */
+void lpc32xx_get_uid(u32 devid[4])
+{
+       int i;
+
+       for (i = 0; i < 4; i++)
+               devid[i] = __raw_readl(LPC32XX_CLKPWR_DEVID(i << 2));
+}
+
+/*
+ * Returns SYSCLK source
+ * 0 = PLL397, 1 = main oscillator
+ */
+int clk_is_sysclk_mainosc(void)
+{
+       if ((__raw_readl(LPC32XX_CLKPWR_SYSCLK_CTRL) &
+               LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * System reset via the watchdog timer
+ */
+void lpc32xx_watchdog_reset(void)
+{
+       /* Make sure WDT clocks are enabled */
+       __raw_writel(LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
+               LPC32XX_CLKPWR_TIMER_CLK_CTRL);
+
+       /* Instant assert of RESETOUT_N with pulse length 1mS */
+       __raw_writel(13000, io_p2v(LPC32XX_WDTIM_BASE + 0x18));
+       __raw_writel(0x70, io_p2v(LPC32XX_WDTIM_BASE + 0xC));
+}
+
+/*
+ * Detects and returns IRAM size for the device variation
+ */
+#define LPC32XX_IRAM_BANK_SIZE SZ_128K
+static u32 iram_size;
+u32 lpc32xx_return_iram_size(void)
+{
+       if (iram_size == 0) {
+               u32 savedval1, savedval2;
+               void __iomem *iramptr1, *iramptr2;
+
+               iramptr1 = io_p2v(LPC32XX_IRAM_BASE);
+               iramptr2 = io_p2v(LPC32XX_IRAM_BASE + LPC32XX_IRAM_BANK_SIZE);
+               savedval1 = __raw_readl(iramptr1);
+               savedval2 = __raw_readl(iramptr2);
+
+               if (savedval1 == savedval2) {
+                       __raw_writel(savedval2 + 1, iramptr2);
+                       if (__raw_readl(iramptr1) == savedval2 + 1)
+                               iram_size = LPC32XX_IRAM_BANK_SIZE;
+                       else
+                               iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
+                       __raw_writel(savedval2, iramptr2);
+               } else
+                       iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
+       }
+
+       return iram_size;
+}
+
+/*
+ * Computes PLL rate from PLL register and input clock
+ */
+u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
+{
+       u32 ilfreq, p, m, n, fcco, fref, cfreq;
+       int mode;
+
+       /*
+        * PLL requirements
+        * ifreq must be >= 1MHz and <= 20MHz
+        * FCCO must be >= 156MHz and <= 320MHz
+        * FREF must be >= 1MHz and <= 27MHz
+        * Assume the passed input data is not valid
+        */
+
+       ilfreq = ifreq;
+       m = pllsetup->pll_m;
+       n = pllsetup->pll_n;
+       p = pllsetup->pll_p;
+
+       mode = (pllsetup->cco_bypass_b15 << 2) |
+               (pllsetup->direct_output_b14 << 1) |
+       pllsetup->fdbk_div_ctrl_b13;
+
+       switch (mode) {
+       case 0x0: /* Non-integer mode */
+               cfreq = (m * ilfreq) / (2 * p * n);
+               fcco = (m * ilfreq) / n;
+               fref = ilfreq / n;
+               break;
+
+       case 0x1: /* integer mode */
+               cfreq = (m * ilfreq) / n;
+               fcco = (m * ilfreq) / (n * 2 * p);
+               fref = ilfreq / n;
+               break;
+
+       case 0x2:
+       case 0x3: /* Direct mode */
+               cfreq = (m * ilfreq) / n;
+               fcco = cfreq;
+               fref = ilfreq / n;
+               break;
+
+       case 0x4:
+       case 0x5: /* Bypass mode */
+               cfreq = ilfreq / (2 * p);
+               fcco = 156000000;
+               fref = 1000000;
+               break;
+
+       case 0x6:
+       case 0x7: /* Direct bypass mode */
+       default:
+               cfreq = ilfreq;
+               fcco = 156000000;
+               fref = 1000000;
+               break;
+       }
+
+       if (fcco < 156000000 || fcco > 320000000)
+               cfreq = 0;
+
+       if (fref < 1000000 || fref > 27000000)
+               cfreq = 0;
+
+       return (u32) cfreq;
+}
+
+u32 clk_get_pclk_div(void)
+{
+       return 1 + ((__raw_readl(LPC32XX_CLKPWR_HCLK_DIV) >> 2) & 0x1F);
+}
+
+static struct map_desc lpc32xx_io_desc[] __initdata = {
+       {
+               .virtual        = IO_ADDRESS(LPC32XX_AHB0_START),
+               .pfn            = __phys_to_pfn(LPC32XX_AHB0_START),
+               .length         = LPC32XX_AHB0_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = IO_ADDRESS(LPC32XX_AHB1_START),
+               .pfn            = __phys_to_pfn(LPC32XX_AHB1_START),
+               .length         = LPC32XX_AHB1_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = IO_ADDRESS(LPC32XX_FABAPB_START),
+               .pfn            = __phys_to_pfn(LPC32XX_FABAPB_START),
+               .length         = LPC32XX_FABAPB_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = IO_ADDRESS(LPC32XX_IRAM_BASE),
+               .pfn            = __phys_to_pfn(LPC32XX_IRAM_BASE),
+               .length         = (LPC32XX_IRAM_BANK_SIZE * 2),
+               .type           = MT_DEVICE
+       },
+};
+
+void __init lpc32xx_map_io(void)
+{
+       iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
+}
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
new file mode 100644 (file)
index 0000000..f82211f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/mach-lpc32xx/common.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2009-2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __LPC32XX_COMMON_H
+#define __LPC32XX_COMMON_H
+
+#include <linux/platform_device.h>
+
+/*
+ * Arch specific platform device structures
+ */
+extern struct platform_device lpc32xx_watchdog_device;
+extern struct platform_device lpc32xx_i2c0_device;
+extern struct platform_device lpc32xx_i2c1_device;
+extern struct platform_device lpc32xx_i2c2_device;
+
+/*
+ * Other arch specific structures and functions
+ */
+extern struct sys_timer lpc32xx_timer;
+extern void __init lpc32xx_init_irq(void);
+extern void __init lpc32xx_map_io(void);
+extern void __init lpc32xx_serial_init(void);
+extern void __init lpc32xx_gpio_init(void);
+
+/*
+ * Structure used for setting up and querying the PLLS
+ */
+struct clk_pll_setup {
+       int analog_on;
+       int cco_bypass_b15;
+       int direct_output_b14;
+       int fdbk_div_ctrl_b13;
+       int pll_p;
+       int pll_n;
+       u32 pll_m;
+};
+
+extern int clk_is_sysclk_mainosc(void);
+extern u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup);
+extern u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval);
+extern u32 clk_get_pclk_div(void);
+
+/*
+ * Returns the LPC32xx unique 128-bit chip ID
+ */
+extern void lpc32xx_get_uid(u32 devid[4]);
+
+extern void lpc32xx_watchdog_reset(void);
+extern u32 lpc32xx_return_iram_size(void);
+
+/*
+ * Pointers used for sizing and copying suspend function data
+ */
+extern int lpc32xx_sys_suspend(void);
+extern int lpc32xx_sys_suspend_sz;
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/gpiolib.c b/arch/arm/mach-lpc32xx/gpiolib.c
new file mode 100644 (file)
index 0000000..69061ea
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * arch/arm/mach-lpc32xx/gpiolib.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+#define LPC32XX_GPIO_P3_INP_STATE              _GPREG(0x000)
+#define LPC32XX_GPIO_P3_OUTP_SET               _GPREG(0x004)
+#define LPC32XX_GPIO_P3_OUTP_CLR               _GPREG(0x008)
+#define LPC32XX_GPIO_P3_OUTP_STATE             _GPREG(0x00C)
+#define LPC32XX_GPIO_P2_DIR_SET                        _GPREG(0x010)
+#define LPC32XX_GPIO_P2_DIR_CLR                        _GPREG(0x014)
+#define LPC32XX_GPIO_P2_DIR_STATE              _GPREG(0x018)
+#define LPC32XX_GPIO_P2_INP_STATE              _GPREG(0x01C)
+#define LPC32XX_GPIO_P2_OUTP_SET               _GPREG(0x020)
+#define LPC32XX_GPIO_P2_OUTP_CLR               _GPREG(0x024)
+#define LPC32XX_GPIO_P2_MUX_SET                        _GPREG(0x028)
+#define LPC32XX_GPIO_P2_MUX_CLR                        _GPREG(0x02C)
+#define LPC32XX_GPIO_P2_MUX_STATE              _GPREG(0x030)
+#define LPC32XX_GPIO_P0_INP_STATE              _GPREG(0x040)
+#define LPC32XX_GPIO_P0_OUTP_SET               _GPREG(0x044)
+#define LPC32XX_GPIO_P0_OUTP_CLR               _GPREG(0x048)
+#define LPC32XX_GPIO_P0_OUTP_STATE             _GPREG(0x04C)
+#define LPC32XX_GPIO_P0_DIR_SET                        _GPREG(0x050)
+#define LPC32XX_GPIO_P0_DIR_CLR                        _GPREG(0x054)
+#define LPC32XX_GPIO_P0_DIR_STATE              _GPREG(0x058)
+#define LPC32XX_GPIO_P1_INP_STATE              _GPREG(0x060)
+#define LPC32XX_GPIO_P1_OUTP_SET               _GPREG(0x064)
+#define LPC32XX_GPIO_P1_OUTP_CLR               _GPREG(0x068)
+#define LPC32XX_GPIO_P1_OUTP_STATE             _GPREG(0x06C)
+#define LPC32XX_GPIO_P1_DIR_SET                        _GPREG(0x070)
+#define LPC32XX_GPIO_P1_DIR_CLR                        _GPREG(0x074)
+#define LPC32XX_GPIO_P1_DIR_STATE              _GPREG(0x078)
+
+#define GPIO012_PIN_TO_BIT(x)                  (1 << (x))
+#define GPIO3_PIN_TO_BIT(x)                    (1 << ((x) + 25))
+#define GPO3_PIN_TO_BIT(x)                     (1 << (x))
+#define GPIO012_PIN_IN_SEL(x, y)               (((x) >> (y)) & 1)
+#define GPIO3_PIN_IN_SHIFT(x)                  ((x) == 5 ? 24 : 10 + (x))
+#define GPIO3_PIN_IN_SEL(x, y)                 ((x) >> GPIO3_PIN_IN_SHIFT(y))
+#define GPIO3_PIN5_IN_SEL(x)                   (((x) >> 24) & 1)
+#define GPI3_PIN_IN_SEL(x, y)                  (((x) >> (y)) & 1)
+
+struct gpio_regs {
+       void __iomem *inp_state;
+       void __iomem *outp_set;
+       void __iomem *outp_clr;
+       void __iomem *dir_set;
+       void __iomem *dir_clr;
+};
+
+/*
+ * GPIO names
+ */
+static const char *gpio_p0_names[LPC32XX_GPIO_P0_MAX] = {
+       "p0.0", "p0.1", "p0.2", "p0.3",
+       "p0.4", "p0.5", "p0.6", "p0.7"
+};
+
+static const char *gpio_p1_names[LPC32XX_GPIO_P1_MAX] = {
+       "p1.0", "p1.1", "p1.2", "p1.3",
+       "p1.4", "p1.5", "p1.6", "p1.7",
+       "p1.8", "p1.9", "p1.10", "p1.11",
+       "p1.12", "p1.13", "p1.14", "p1.15",
+       "p1.16", "p1.17", "p1.18", "p1.19",
+       "p1.20", "p1.21", "p1.22", "p1.23",
+};
+
+static const char *gpio_p2_names[LPC32XX_GPIO_P2_MAX] = {
+       "p2.0", "p2.1", "p2.2", "p2.3",
+       "p2.4", "p2.5", "p2.6", "p2.7",
+       "p2.8", "p2.9", "p2.10", "p2.11",
+       "p2.12"
+};
+
+static const char *gpio_p3_names[LPC32XX_GPIO_P3_MAX] = {
+       "gpi000", "gpio01", "gpio02", "gpio03",
+       "gpio04", "gpio05"
+};
+
+static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = {
+       "gpi00", "gpi01", "gpi02", "gpi03",
+       "gpi04", "gpi05", "gpi06", "gpi07",
+       "gpi08", "gpi09",  NULL,    NULL,
+        NULL,    NULL,    NULL,   "gpi15",
+       "gpi16", "gpi17", "gpi18", "gpi19",
+       "gpi20", "gpi21", "gpi22", "gpi23",
+       "gpi24", "gpi25", "gpi26", "gpi27"
+};
+
+static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = {
+       "gpo00", "gpo01", "gpo02", "gpo03",
+       "gpo04", "gpo05", "gpo06", "gpo07",
+       "gpo08", "gpo09", "gpo10", "gpo11",
+       "gpo12", "gpo13", "gpo14", "gpo15",
+       "gpo16", "gpo17", "gpo18", "gpo19",
+       "gpo20", "gpo21", "gpo22", "gpo23"
+};
+
+static struct gpio_regs gpio_grp_regs_p0 = {
+       .inp_state      = LPC32XX_GPIO_P0_INP_STATE,
+       .outp_set       = LPC32XX_GPIO_P0_OUTP_SET,
+       .outp_clr       = LPC32XX_GPIO_P0_OUTP_CLR,
+       .dir_set        = LPC32XX_GPIO_P0_DIR_SET,
+       .dir_clr        = LPC32XX_GPIO_P0_DIR_CLR,
+};
+
+static struct gpio_regs gpio_grp_regs_p1 = {
+       .inp_state      = LPC32XX_GPIO_P1_INP_STATE,
+       .outp_set       = LPC32XX_GPIO_P1_OUTP_SET,
+       .outp_clr       = LPC32XX_GPIO_P1_OUTP_CLR,
+       .dir_set        = LPC32XX_GPIO_P1_DIR_SET,
+       .dir_clr        = LPC32XX_GPIO_P1_DIR_CLR,
+};
+
+static struct gpio_regs gpio_grp_regs_p2 = {
+       .inp_state      = LPC32XX_GPIO_P2_INP_STATE,
+       .outp_set       = LPC32XX_GPIO_P2_OUTP_SET,
+       .outp_clr       = LPC32XX_GPIO_P2_OUTP_CLR,
+       .dir_set        = LPC32XX_GPIO_P2_DIR_SET,
+       .dir_clr        = LPC32XX_GPIO_P2_DIR_CLR,
+};
+
+static struct gpio_regs gpio_grp_regs_p3 = {
+       .inp_state      = LPC32XX_GPIO_P3_INP_STATE,
+       .outp_set       = LPC32XX_GPIO_P3_OUTP_SET,
+       .outp_clr       = LPC32XX_GPIO_P3_OUTP_CLR,
+       .dir_set        = LPC32XX_GPIO_P2_DIR_SET,
+       .dir_clr        = LPC32XX_GPIO_P2_DIR_CLR,
+};
+
+struct lpc32xx_gpio_chip {
+       struct gpio_chip        chip;
+       struct gpio_regs        *gpio_grp;
+};
+
+static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
+       struct gpio_chip *gpc)
+{
+       return container_of(gpc, struct lpc32xx_gpio_chip, chip);
+}
+
+static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
+       unsigned pin, int input)
+{
+       if (input)
+               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+                       group->gpio_grp->dir_clr);
+       else
+               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+                       group->gpio_grp->dir_set);
+}
+
+static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
+       unsigned pin, int input)
+{
+       u32 u = GPIO3_PIN_TO_BIT(pin);
+
+       if (input)
+               __raw_writel(u, group->gpio_grp->dir_clr);
+       else
+               __raw_writel(u, group->gpio_grp->dir_set);
+}
+
+static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
+       unsigned pin, int high)
+{
+       if (high)
+               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+                       group->gpio_grp->outp_set);
+       else
+               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+                       group->gpio_grp->outp_clr);
+}
+
+static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
+       unsigned pin, int high)
+{
+       u32 u = GPIO3_PIN_TO_BIT(pin);
+
+       if (high)
+               __raw_writel(u, group->gpio_grp->outp_set);
+       else
+               __raw_writel(u, group->gpio_grp->outp_clr);
+}
+
+static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
+       unsigned pin, int high)
+{
+       if (high)
+               __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
+       else
+               __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
+}
+
+static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
+       unsigned pin)
+{
+       return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state),
+               pin);
+}
+
+static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
+       unsigned pin)
+{
+       int state = __raw_readl(group->gpio_grp->inp_state);
+
+       /*
+        * P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped
+        * to bits 10..14, while GPIOP3-5 is mapped to bit 24.
+        */
+       return GPIO3_PIN_IN_SEL(state, pin);
+}
+
+static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
+       unsigned pin)
+{
+       return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
+}
+
+/*
+ * GENERIC_GPIO primitives.
+ */
+static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
+       unsigned pin)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpio_dir_p012(group, pin, 1);
+
+       return 0;
+}
+
+static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
+       unsigned pin)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpio_dir_p3(group, pin, 1);
+
+       return 0;
+}
+
+static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip,
+       unsigned pin)
+{
+       return 0;
+}
+
+static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       return __get_gpio_state_p012(group, pin);
+}
+
+static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       return __get_gpio_state_p3(group, pin);
+}
+
+static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       return __get_gpi_state_p3(group, pin);
+}
+
+static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
+       int value)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpio_dir_p012(group, pin, 0);
+
+       return 0;
+}
+
+static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
+       int value)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpio_dir_p3(group, pin, 0);
+
+       return 0;
+}
+
+static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
+       int value)
+{
+       return 0;
+}
+
+static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
+       int value)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpio_level_p012(group, pin, value);
+}
+
+static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
+       int value)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpio_level_p3(group, pin, value);
+}
+
+static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
+       int value)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       __set_gpo_level_p3(group, pin, value);
+}
+
+static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
+{
+       if (pin < chip->ngpio)
+               return 0;
+
+       return -EINVAL;
+}
+
+static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
+       {
+               .chip = {
+                       .label                  = "gpio_p0",
+                       .direction_input        = lpc32xx_gpio_dir_input_p012,
+                       .get                    = lpc32xx_gpio_get_value_p012,
+                       .direction_output       = lpc32xx_gpio_dir_output_p012,
+                       .set                    = lpc32xx_gpio_set_value_p012,
+                       .request                = lpc32xx_gpio_request,
+                       .base                   = LPC32XX_GPIO_P0_GRP,
+                       .ngpio                  = LPC32XX_GPIO_P0_MAX,
+                       .names                  = gpio_p0_names,
+                       .can_sleep              = 0,
+               },
+               .gpio_grp = &gpio_grp_regs_p0,
+       },
+       {
+               .chip = {
+                       .label                  = "gpio_p1",
+                       .direction_input        = lpc32xx_gpio_dir_input_p012,
+                       .get                    = lpc32xx_gpio_get_value_p012,
+                       .direction_output       = lpc32xx_gpio_dir_output_p012,
+                       .set                    = lpc32xx_gpio_set_value_p012,
+                       .request                = lpc32xx_gpio_request,
+                       .base                   = LPC32XX_GPIO_P1_GRP,
+                       .ngpio                  = LPC32XX_GPIO_P1_MAX,
+                       .names                  = gpio_p1_names,
+                       .can_sleep              = 0,
+               },
+               .gpio_grp = &gpio_grp_regs_p1,
+       },
+       {
+               .chip = {
+                       .label                  = "gpio_p2",
+                       .direction_input        = lpc32xx_gpio_dir_input_p012,
+                       .get                    = lpc32xx_gpio_get_value_p012,
+                       .direction_output       = lpc32xx_gpio_dir_output_p012,
+                       .set                    = lpc32xx_gpio_set_value_p012,
+                       .request                = lpc32xx_gpio_request,
+                       .base                   = LPC32XX_GPIO_P2_GRP,
+                       .ngpio                  = LPC32XX_GPIO_P2_MAX,
+                       .names                  = gpio_p2_names,
+                       .can_sleep              = 0,
+               },
+               .gpio_grp = &gpio_grp_regs_p2,
+       },
+       {
+               .chip = {
+                       .label                  = "gpio_p3",
+                       .direction_input        = lpc32xx_gpio_dir_input_p3,
+                       .get                    = lpc32xx_gpio_get_value_p3,
+                       .direction_output       = lpc32xx_gpio_dir_output_p3,
+                       .set                    = lpc32xx_gpio_set_value_p3,
+                       .request                = lpc32xx_gpio_request,
+                       .base                   = LPC32XX_GPIO_P3_GRP,
+                       .ngpio                  = LPC32XX_GPIO_P3_MAX,
+                       .names                  = gpio_p3_names,
+                       .can_sleep              = 0,
+               },
+               .gpio_grp = &gpio_grp_regs_p3,
+       },
+       {
+               .chip = {
+                       .label                  = "gpi_p3",
+                       .direction_input        = lpc32xx_gpio_dir_in_always,
+                       .get                    = lpc32xx_gpi_get_value,
+                       .request                = lpc32xx_gpio_request,
+                       .base                   = LPC32XX_GPI_P3_GRP,
+                       .ngpio                  = LPC32XX_GPI_P3_MAX,
+                       .names                  = gpi_p3_names,
+                       .can_sleep              = 0,
+               },
+               .gpio_grp = &gpio_grp_regs_p3,
+       },
+       {
+               .chip = {
+                       .label                  = "gpo_p3",
+                       .direction_output       = lpc32xx_gpio_dir_out_always,
+                       .set                    = lpc32xx_gpo_set_value,
+                       .request                = lpc32xx_gpio_request,
+                       .base                   = LPC32XX_GPO_P3_GRP,
+                       .ngpio                  = LPC32XX_GPO_P3_MAX,
+                       .names                  = gpo_p3_names,
+                       .can_sleep              = 0,
+               },
+               .gpio_grp = &gpio_grp_regs_p3,
+       },
+};
+
+void __init lpc32xx_gpio_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++)
+               gpiochip_add(&lpc32xx_gpiochip[i].chip);
+}
similarity index 57%
rename from arch/arm/plat-mxc/include/mach/board-pcm043.h
rename to arch/arm/mach-lpc32xx/include/mach/clkdev.h
index 1ac4e1682e5c2f8840a778fd65a6cabf304927ad..9bf0637e29cefd9c6f5fd0c629d06def6305b9b1 100644 (file)
@@ -1,5 +1,9 @@
 /*
- *  Copyright (C) 2008 Sascha Hauer, Pengutronix
+ * arch/arm/mach-lpc32xx/include/mach/clkdev.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 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 __ASM_ARCH_MXC_BOARD_PCM043_H__
-#define __ASM_ARCH_MXC_BOARD_PCM043_H__
+#ifndef __ASM_ARCH_CLKDEV_H
+#define __ASM_ARCH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
 
-#endif /* __ASM_ARCH_MXC_BOARD_PCM043_H__ */
+#endif
similarity index 55%
rename from arch/arm/plat-mxc/include/mach/board-mx35pdk.h
rename to arch/arm/mach-lpc32xx/include/mach/debug-macro.S
index 383f1c04df06b0e8c56f84191366e120696e35e2..621744d6b15205954bbad0980b89a2315c343d3f 100644 (file)
@@ -1,5 +1,9 @@
 /*
- *  Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved
+ * arch/arm/mach-lpc32xx/include/mach/debug-macro.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 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 __ASM_ARCH_MXC_BOARD_MX35PDK_H__
-#define __ASM_ARCH_MXC_BOARD_MX35PDK_H__
+/*
+ * Debug output is hardcoded to standard UART 5
+*/
+
+       .macro  addruart,rx, tmp
+       mrc     p15, 0, \rx, c1, c0
+       tst     \rx, #1                         @ MMU enabled?
+       ldreq   \rx, =0x40090000
+       ldrne   \rx, =0xF4090000
+       .endm
 
-#endif /* __ASM_ARCH_MXC_BOARD_MX35PDK_H__ */
+#define UART_SHIFT     2
+#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..870227c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/entry-macro.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#define LPC32XX_INTC_MASKED_STATUS_OFS 0x8
+
+       .macro  disable_fiq
+       .endm
+
+       .macro  get_irqnr_preamble, base, tmp
+       ldr     \base, =IO_ADDRESS(LPC32XX_MIC_BASE)
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+/*
+ * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
+ * as set if an interrupt is pending.
+ */
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+       ldr     \irqstat, [\base, #LPC32XX_INTC_MASKED_STATUS_OFS]
+       clz     \irqnr, \irqstat
+       rsb     \irqnr, \irqnr, #31
+       teq     \irqstat, #0
+       .endm
+
+       .macro  irq_prio_table
+       .endm
+
diff --git a/arch/arm/mach-lpc32xx/include/mach/gpio.h b/arch/arm/mach-lpc32xx/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..67d03da
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/gpio.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+/*
+ * Note!
+ * Muxed GP pins need to be setup to the GP state in the board level
+ * code prior to using this driver.
+ * GPI pins : 28xP3 group
+ * GPO pins : 24xP3 group
+ * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group
+ */
+
+#define LPC32XX_GPIO_P0_MAX 8
+#define LPC32XX_GPIO_P1_MAX 24
+#define LPC32XX_GPIO_P2_MAX 13
+#define LPC32XX_GPIO_P3_MAX 6
+#define LPC32XX_GPI_P3_MAX 28
+#define LPC32XX_GPO_P3_MAX 24
+
+#define LPC32XX_GPIO_P0_GRP 0
+#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX)
+#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX)
+#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX)
+#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX)
+#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX)
+
+/*
+ * A specific GPIO can be selected with this macro
+ * ie, GPIO_05 can be selected with LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
+ * See the LPC32x0 User's guide for GPIO group numbers
+ */
+#define LPC32XX_GPIO(x, y) ((x) + (y))
+
+static inline int gpio_get_value(unsigned gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+       return __gpio_to_irq(gpio);
+}
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/hardware.h b/arch/arm/mach-lpc32xx/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..33e1dde
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/hardware.h
+ *
+ * Copyright (c) 2005 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/*
+ * Start of virtual addresses for IO devices
+ */
+#define IO_BASE                0xF0000000
+
+/*
+ * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0
+ */
+#define IO_ADDRESS(x)  (((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\
+                        IO_BASE)
+
+#define io_p2v(x)      ((void __iomem *) (unsigned long) IO_ADDRESS(x))
+#define io_v2p(x)      ((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff))
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/i2c.h b/arch/arm/mach-lpc32xx/include/mach/i2c.h
new file mode 100644 (file)
index 0000000..034dc92
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * PNX4008-specific tweaks for I2C IP3204 block
+ *
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __ASM_ARCH_I2C_H
+#define __ASM_ARCH_I2C_H
+
+enum {
+       mstatus_tdi = 0x00000001,
+       mstatus_afi = 0x00000002,
+       mstatus_nai = 0x00000004,
+       mstatus_drmi = 0x00000008,
+       mstatus_active = 0x00000020,
+       mstatus_scl = 0x00000040,
+       mstatus_sda = 0x00000080,
+       mstatus_rff = 0x00000100,
+       mstatus_rfe = 0x00000200,
+       mstatus_tff = 0x00000400,
+       mstatus_tfe = 0x00000800,
+};
+
+enum {
+       mcntrl_tdie = 0x00000001,
+       mcntrl_afie = 0x00000002,
+       mcntrl_naie = 0x00000004,
+       mcntrl_drmie = 0x00000008,
+       mcntrl_daie = 0x00000020,
+       mcntrl_rffie = 0x00000040,
+       mcntrl_tffie = 0x00000080,
+       mcntrl_reset = 0x00000100,
+       mcntrl_cdbmode = 0x00000400,
+};
+
+enum {
+       rw_bit = 1 << 0,
+       start_bit = 1 << 8,
+       stop_bit = 1 << 9,
+};
+
+#define I2C_REG_RX(a)  ((a)->ioaddr)           /* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a)  ((a)->ioaddr)           /* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a) ((a)->ioaddr + 0x04)    /* Status reg (RO) */
+#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08)    /* Ctl reg */
+#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c)    /* Clock divider low */
+#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10)    /* Clock divider high */
+#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14)    /* I2C address */
+#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18)    /* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c)    /* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20)    /* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24)    /* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28)    /* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a)        ((a)->ioaddr + 0x2c)    /* Tx slave FIFO level (RO) */
+
+#define I2C_CHIP_NAME          "PNX4008-I2C"
+
+#endif                         /* __ASM_ARCH_I2C_H */
similarity index 57%
rename from arch/arm/plat-mxc/include/mach/board-pcm037.h
rename to arch/arm/mach-lpc32xx/include/mach/io.h
index 13411709b13a067bdc8c7adf9ec6d984acb98f75..9b59ab5cef8942d13108fed8fe8c01c6217ea3b8 100644 (file)
@@ -1,5 +1,9 @@
 /*
- *  Copyright (C) 2008 Sascha Hauer, Pengutronix
+ * arch/arm/mach-lpc32xx/include/mach/io.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 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 __ASM_ARCH_MXC_BOARD_PCM037_H__
-#define __ASM_ARCH_MXC_BOARD_PCM037_H__
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
-#endif /* __ASM_ARCH_MXC_BOARD_PCM037_H__ */
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/irqs.h b/arch/arm/mach-lpc32xx/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..2667f52
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/irqs.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARM_ARCH_IRQS_H
+#define __ASM_ARM_ARCH_IRQS_H
+
+#define LPC32XX_SIC1_IRQ(n)            (32 + (n))
+#define LPC32XX_SIC2_IRQ(n)            (64 + (n))
+
+/*
+ * MIC interrupts
+ */
+#define IRQ_LPC32XX_SUB1IRQ            0
+#define IRQ_LPC32XX_SUB2IRQ            1
+#define IRQ_LPC32XX_PWM3               3
+#define IRQ_LPC32XX_PWM4               4
+#define IRQ_LPC32XX_HSTIMER            5
+#define IRQ_LPC32XX_WATCH              6
+#define IRQ_LPC32XX_UART_IIR3          7
+#define IRQ_LPC32XX_UART_IIR4          8
+#define IRQ_LPC32XX_UART_IIR5          9
+#define IRQ_LPC32XX_UART_IIR6          10
+#define IRQ_LPC32XX_FLASH              11
+#define IRQ_LPC32XX_SD1                        13
+#define IRQ_LPC32XX_LCD                        14
+#define IRQ_LPC32XX_SD0                        15
+#define IRQ_LPC32XX_TIMER0             16
+#define IRQ_LPC32XX_TIMER1             17
+#define IRQ_LPC32XX_TIMER2             18
+#define IRQ_LPC32XX_TIMER3             19
+#define IRQ_LPC32XX_SSP0               20
+#define IRQ_LPC32XX_SSP1               21
+#define IRQ_LPC32XX_I2S0               22
+#define IRQ_LPC32XX_I2S1               23
+#define IRQ_LPC32XX_UART_IIR7          24
+#define IRQ_LPC32XX_UART_IIR2          25
+#define IRQ_LPC32XX_UART_IIR1          26
+#define IRQ_LPC32XX_MSTIMER            27
+#define IRQ_LPC32XX_DMA                        28
+#define IRQ_LPC32XX_ETHERNET           29
+#define IRQ_LPC32XX_SUB1FIQ            30
+#define IRQ_LPC32XX_SUB2FIQ            31
+
+/*
+ * SIC1 interrupts start at offset 32
+ */
+#define IRQ_LPC32XX_JTAG_COMM_TX       LPC32XX_SIC1_IRQ(1)
+#define IRQ_LPC32XX_JTAG_COMM_RX       LPC32XX_SIC1_IRQ(2)
+#define IRQ_LPC32XX_GPI_11             LPC32XX_SIC1_IRQ(4)
+#define IRQ_LPC32XX_TS_P               LPC32XX_SIC1_IRQ(6)
+#define IRQ_LPC32XX_TS_IRQ             LPC32XX_SIC1_IRQ(7)
+#define IRQ_LPC32XX_TS_AUX             LPC32XX_SIC1_IRQ(8)
+#define IRQ_LPC32XX_SPI2               LPC32XX_SIC1_IRQ(12)
+#define IRQ_LPC32XX_PLLUSB             LPC32XX_SIC1_IRQ(13)
+#define IRQ_LPC32XX_PLLHCLK            LPC32XX_SIC1_IRQ(14)
+#define IRQ_LPC32XX_PLL397             LPC32XX_SIC1_IRQ(17)
+#define IRQ_LPC32XX_I2C_2              LPC32XX_SIC1_IRQ(18)
+#define IRQ_LPC32XX_I2C_1              LPC32XX_SIC1_IRQ(19)
+#define IRQ_LPC32XX_RTC                        LPC32XX_SIC1_IRQ(20)
+#define IRQ_LPC32XX_KEY                        LPC32XX_SIC1_IRQ(22)
+#define IRQ_LPC32XX_SPI1               LPC32XX_SIC1_IRQ(23)
+#define IRQ_LPC32XX_SW                 LPC32XX_SIC1_IRQ(24)
+#define IRQ_LPC32XX_USB_OTG_TIMER      LPC32XX_SIC1_IRQ(25)
+#define IRQ_LPC32XX_USB_OTG_ATX                LPC32XX_SIC1_IRQ(26)
+#define IRQ_LPC32XX_USB_HOST           LPC32XX_SIC1_IRQ(27)
+#define IRQ_LPC32XX_USB_DEV_DMA                LPC32XX_SIC1_IRQ(28)
+#define IRQ_LPC32XX_USB_DEV_LP         LPC32XX_SIC1_IRQ(29)
+#define IRQ_LPC32XX_USB_DEV_HP         LPC32XX_SIC1_IRQ(30)
+#define IRQ_LPC32XX_USB_I2C            LPC32XX_SIC1_IRQ(31)
+
+/*
+ * SIC2 interrupts start at offset 64
+ */
+#define IRQ_LPC32XX_GPIO_00            LPC32XX_SIC2_IRQ(0)
+#define IRQ_LPC32XX_GPIO_01            LPC32XX_SIC2_IRQ(1)
+#define IRQ_LPC32XX_GPIO_02            LPC32XX_SIC2_IRQ(2)
+#define IRQ_LPC32XX_GPIO_03            LPC32XX_SIC2_IRQ(3)
+#define IRQ_LPC32XX_GPIO_04            LPC32XX_SIC2_IRQ(4)
+#define IRQ_LPC32XX_GPIO_05            LPC32XX_SIC2_IRQ(5)
+#define IRQ_LPC32XX_SPI2_DATAIN                LPC32XX_SIC2_IRQ(6)
+#define IRQ_LPC32XX_U2_HCTS            LPC32XX_SIC2_IRQ(7)
+#define IRQ_LPC32XX_P0_P1_IRQ          LPC32XX_SIC2_IRQ(8)
+#define IRQ_LPC32XX_GPI_08             LPC32XX_SIC2_IRQ(9)
+#define IRQ_LPC32XX_GPI_09             LPC32XX_SIC2_IRQ(10)
+#define IRQ_LPC32XX_GPI_19             LPC32XX_SIC2_IRQ(11)
+#define IRQ_LPC32XX_U7_HCTS            LPC32XX_SIC2_IRQ(12)
+#define IRQ_LPC32XX_GPI_07             LPC32XX_SIC2_IRQ(15)
+#define IRQ_LPC32XX_SDIO               LPC32XX_SIC2_IRQ(18)
+#define IRQ_LPC32XX_U5_RX              LPC32XX_SIC2_IRQ(19)
+#define IRQ_LPC32XX_SPI1_DATAIN                LPC32XX_SIC2_IRQ(20)
+#define IRQ_LPC32XX_GPI_00             LPC32XX_SIC2_IRQ(22)
+#define IRQ_LPC32XX_GPI_01             LPC32XX_SIC2_IRQ(23)
+#define IRQ_LPC32XX_GPI_02             LPC32XX_SIC2_IRQ(24)
+#define IRQ_LPC32XX_GPI_03             LPC32XX_SIC2_IRQ(25)
+#define IRQ_LPC32XX_GPI_04             LPC32XX_SIC2_IRQ(26)
+#define IRQ_LPC32XX_GPI_05             LPC32XX_SIC2_IRQ(27)
+#define IRQ_LPC32XX_GPI_06             LPC32XX_SIC2_IRQ(28)
+#define IRQ_LPC32XX_SYSCLK             LPC32XX_SIC2_IRQ(31)
+
+#define NR_IRQS                                96
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/memory.h b/arch/arm/mach-lpc32xx/include/mach/memory.h
new file mode 100644 (file)
index 0000000..044e1ac
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/memory.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset of bank 0
+ */
+#define PHYS_OFFSET    UL(0x80000000)
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/platform.h b/arch/arm/mach-lpc32xx/include/mach/platform.h
new file mode 100644 (file)
index 0000000..14ea8d1
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/platform.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARCH_PLATFORM_H
+#define __ASM_ARCH_PLATFORM_H
+
+#define _SBF(f, v)                             ((v) << (f))
+#define _BIT(n)                                        _SBF(n, 1)
+
+/*
+ * AHB 0 physical base addresses
+ */
+#define LPC32XX_SLC_BASE                       0x20020000
+#define LPC32XX_SSP0_BASE                      0x20084000
+#define LPC32XX_SPI1_BASE                      0x20088000
+#define LPC32XX_SSP1_BASE                      0x2008C000
+#define LPC32XX_SPI2_BASE                      0x20090000
+#define LPC32XX_I2S0_BASE                      0x20094000
+#define LPC32XX_SD_BASE                                0x20098000
+#define LPC32XX_I2S1_BASE                      0x2009C000
+#define LPC32XX_MLC_BASE                       0x200A8000
+#define LPC32XX_AHB0_START                     LPC32XX_SLC_BASE
+#define LPC32XX_AHB0_SIZE                      0x00089000
+
+/*
+ * AHB 1 physical base addresses
+ */
+#define LPC32XX_DMA_BASE                       0x31000000
+#define LPC32XX_USB_BASE                       0x31020000
+#define LPC32XX_USBH_BASE                      0x31020000
+#define LPC32XX_USB_OTG_BASE                   0x31020000
+#define LPC32XX_OTG_I2C_BASE                   0x31020300
+#define LPC32XX_LCD_BASE                       0x31040000
+#define LPC32XX_ETHERNET_BASE                  0x31060000
+#define LPC32XX_EMC_BASE                       0x31080000
+#define LPC32XX_ETB_CFG_BASE                   0x310C0000
+#define LPC32XX_ETB_DATA_BASE                  0x310E0000
+#define LPC32XX_AHB1_START                     LPC32XX_DMA_BASE
+#define LPC32XX_AHB1_SIZE                      0x000E1000
+
+/*
+ * FAB physical base addresses
+ */
+#define LPC32XX_CLK_PM_BASE                    0x40004000
+#define LPC32XX_MIC_BASE                       0x40008000
+#define LPC32XX_SIC1_BASE                      0x4000C000
+#define LPC32XX_SIC2_BASE                      0x40010000
+#define LPC32XX_HS_UART1_BASE                  0x40014000
+#define LPC32XX_HS_UART2_BASE                  0x40018000
+#define LPC32XX_HS_UART7_BASE                  0x4001C000
+#define LPC32XX_RTC_BASE                       0x40024000
+#define LPC32XX_RTC_RAM_BASE                   0x40024080
+#define LPC32XX_GPIO_BASE                      0x40028000
+#define LPC32XX_PWM3_BASE                      0x4002C000
+#define LPC32XX_PWM4_BASE                      0x40030000
+#define LPC32XX_MSTIM_BASE                     0x40034000
+#define LPC32XX_HSTIM_BASE                     0x40038000
+#define LPC32XX_WDTIM_BASE                     0x4003C000
+#define LPC32XX_DEBUG_CTRL_BASE                        0x40040000
+#define LPC32XX_TIMER0_BASE                    0x40044000
+#define LPC32XX_ADC_BASE                       0x40048000
+#define LPC32XX_TIMER1_BASE                    0x4004C000
+#define LPC32XX_KSCAN_BASE                     0x40050000
+#define LPC32XX_UART_CTRL_BASE                 0x40054000
+#define LPC32XX_TIMER2_BASE                    0x40058000
+#define LPC32XX_PWM1_BASE                      0x4005C000
+#define LPC32XX_PWM2_BASE                      0x4005C004
+#define LPC32XX_TIMER3_BASE                    0x40060000
+
+/*
+ * APB physical base addresses
+ */
+#define LPC32XX_UART3_BASE                     0x40080000
+#define LPC32XX_UART4_BASE                     0x40088000
+#define LPC32XX_UART5_BASE                     0x40090000
+#define LPC32XX_UART6_BASE                     0x40098000
+#define LPC32XX_I2C1_BASE                      0x400A0000
+#define LPC32XX_I2C2_BASE                      0x400A8000
+
+/*
+ * FAB and APB base and sizing
+ */
+#define LPC32XX_FABAPB_START                   LPC32XX_CLK_PM_BASE
+#define LPC32XX_FABAPB_SIZE                    0x000A5000
+
+/*
+ * Internal memory bases and sizes
+ */
+#define LPC32XX_IRAM_BASE                      0x08000000
+#define LPC32XX_IROM_BASE                      0x0C000000
+
+/*
+ * External Static Memory Bank Address Space Bases
+ */
+#define LPC32XX_EMC_CS0_BASE                   0xE0000000
+#define LPC32XX_EMC_CS1_BASE                   0xE1000000
+#define LPC32XX_EMC_CS2_BASE                   0xE2000000
+#define LPC32XX_EMC_CS3_BASE                   0xE3000000
+
+/*
+ * External SDRAM Memory Bank Address Space Bases
+ */
+#define LPC32XX_EMC_DYCS0_BASE                 0x80000000
+#define LPC32XX_EMC_DYCS1_BASE                 0xA0000000
+
+/*
+ * Clock and crystal information
+ */
+#define LPC32XX_MAIN_OSC_FREQ                  13000000
+#define LPC32XX_CLOCK_OSC_FREQ                 32768
+
+/*
+ * Clock and Power control register offsets
+ */
+#define _PMREG(x)                              io_p2v(LPC32XX_CLK_PM_BASE +\
+                                               (x))
+#define LPC32XX_CLKPWR_DEBUG_CTRL              _PMREG(0x000)
+#define LPC32XX_CLKPWR_BOOTMAP                 _PMREG(0x014)
+#define LPC32XX_CLKPWR_P01_ER                  _PMREG(0x018)
+#define LPC32XX_CLKPWR_USBCLK_PDIV             _PMREG(0x01C)
+#define LPC32XX_CLKPWR_INT_ER                  _PMREG(0x020)
+#define LPC32XX_CLKPWR_INT_RS                  _PMREG(0x024)
+#define LPC32XX_CLKPWR_INT_SR                  _PMREG(0x028)
+#define LPC32XX_CLKPWR_INT_AP                  _PMREG(0x02C)
+#define LPC32XX_CLKPWR_PIN_ER                  _PMREG(0x030)
+#define LPC32XX_CLKPWR_PIN_RS                  _PMREG(0x034)
+#define LPC32XX_CLKPWR_PIN_SR                  _PMREG(0x038)
+#define LPC32XX_CLKPWR_PIN_AP                  _PMREG(0x03C)
+#define LPC32XX_CLKPWR_HCLK_DIV                        _PMREG(0x040)
+#define LPC32XX_CLKPWR_PWR_CTRL                        _PMREG(0x044)
+#define LPC32XX_CLKPWR_PLL397_CTRL             _PMREG(0x048)
+#define LPC32XX_CLKPWR_MAIN_OSC_CTRL           _PMREG(0x04C)
+#define LPC32XX_CLKPWR_SYSCLK_CTRL             _PMREG(0x050)
+#define LPC32XX_CLKPWR_LCDCLK_CTRL             _PMREG(0x054)
+#define LPC32XX_CLKPWR_HCLKPLL_CTRL            _PMREG(0x058)
+#define LPC32XX_CLKPWR_ADC_CLK_CTRL_1          _PMREG(0x060)
+#define LPC32XX_CLKPWR_USB_CTRL                        _PMREG(0x064)
+#define LPC32XX_CLKPWR_SDRAMCLK_CTRL           _PMREG(0x068)
+#define LPC32XX_CLKPWR_DDR_LAP_NOM             _PMREG(0x06C)
+#define LPC32XX_CLKPWR_DDR_LAP_COUNT           _PMREG(0x070)
+#define LPC32XX_CLKPWR_DDR_LAP_DELAY           _PMREG(0x074)
+#define LPC32XX_CLKPWR_SSP_CLK_CTRL            _PMREG(0x078)
+#define LPC32XX_CLKPWR_I2S_CLK_CTRL            _PMREG(0x07C)
+#define LPC32XX_CLKPWR_MS_CTRL                 _PMREG(0x080)
+#define LPC32XX_CLKPWR_MACCLK_CTRL             _PMREG(0x090)
+#define LPC32XX_CLKPWR_TEST_CLK_SEL            _PMREG(0x0A4)
+#define LPC32XX_CLKPWR_SFW_INT                 _PMREG(0x0A8)
+#define LPC32XX_CLKPWR_I2C_CLK_CTRL            _PMREG(0x0AC)
+#define LPC32XX_CLKPWR_KEY_CLK_CTRL            _PMREG(0x0B0)
+#define LPC32XX_CLKPWR_ADC_CLK_CTRL            _PMREG(0x0B4)
+#define LPC32XX_CLKPWR_PWM_CLK_CTRL            _PMREG(0x0B8)
+#define LPC32XX_CLKPWR_TIMER_CLK_CTRL          _PMREG(0x0BC)
+#define LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1  _PMREG(0x0C0)
+#define LPC32XX_CLKPWR_SPI_CLK_CTRL            _PMREG(0x0C4)
+#define LPC32XX_CLKPWR_NAND_CLK_CTRL           _PMREG(0x0C8)
+#define LPC32XX_CLKPWR_UART3_CLK_CTRL          _PMREG(0x0D0)
+#define LPC32XX_CLKPWR_UART4_CLK_CTRL          _PMREG(0x0D4)
+#define LPC32XX_CLKPWR_UART5_CLK_CTRL          _PMREG(0x0D8)
+#define LPC32XX_CLKPWR_UART6_CLK_CTRL          _PMREG(0x0DC)
+#define LPC32XX_CLKPWR_IRDA_CLK_CTRL           _PMREG(0x0E0)
+#define LPC32XX_CLKPWR_UART_CLK_CTRL           _PMREG(0x0E4)
+#define LPC32XX_CLKPWR_DMA_CLK_CTRL            _PMREG(0x0E8)
+#define LPC32XX_CLKPWR_AUTOCLOCK               _PMREG(0x0EC)
+#define LPC32XX_CLKPWR_DEVID(x)                        _PMREG(0x130 + (x))
+
+/*
+ * clkpwr_debug_ctrl register definitions
+*/
+#define LPC32XX_CLKPWR_VFP_CLOCK_ENABLE_BIT    _BIT(4)
+
+/*
+ * clkpwr_bootmap register definitions
+ */
+#define LPC32XX_CLKPWR_BOOTMAP_SEL_BIT         _BIT(1)
+
+/*
+ * clkpwr_start_gpio register bit definitions
+ */
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO23_BIT      _BIT(31)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO22_BIT      _BIT(30)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO21_BIT      _BIT(29)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO20_BIT      _BIT(28)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO19_BIT      _BIT(27)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO18_BIT      _BIT(26)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO17_BIT      _BIT(25)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO16_BIT      _BIT(24)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO15_BIT      _BIT(23)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO14_BIT      _BIT(22)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO13_BIT      _BIT(21)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO12_BIT      _BIT(20)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO11_BIT      _BIT(19)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO10_BIT      _BIT(18)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO9_BIT       _BIT(17)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO8_BIT       _BIT(16)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO7_BIT       _BIT(15)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO6_BIT       _BIT(14)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO5_BIT       _BIT(13)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO4_BIT       _BIT(12)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO3_BIT       _BIT(11)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO2_BIT       _BIT(10)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO1_BIT       _BIT(9)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO0_BIT       _BIT(8)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO7_BIT       _BIT(7)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO6_BIT       _BIT(6)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO5_BIT       _BIT(5)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO4_BIT       _BIT(4)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO3_BIT       _BIT(3)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO2_BIT       _BIT(2)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO1_BIT       _BIT(1)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO0_BIT       _BIT(0)
+
+/*
+ * clkpwr_usbclk_pdiv register definitions
+ */
+#define LPC32XX_CLKPWR_USBPDIV_PLL_MASK                0xF
+
+/*
+ * clkpwr_start_int, clkpwr_start_raw_sts_int, clkpwr_start_sts_int,
+ * clkpwr_start_pol_int, register bit definitions
+ */
+#define LPC32XX_CLKPWR_INTSRC_ADC_BIT          _BIT(31)
+#define LPC32XX_CLKPWR_INTSRC_TS_P_BIT         _BIT(30)
+#define LPC32XX_CLKPWR_INTSRC_TS_AUX_BIT       _BIT(29)
+#define LPC32XX_CLKPWR_INTSRC_USBAHNEEDCLK_BIT _BIT(26)
+#define LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT      _BIT(25)
+#define LPC32XX_CLKPWR_INTSRC_RTC_BIT          _BIT(24)
+#define LPC32XX_CLKPWR_INTSRC_USBNEEDCLK_BIT   _BIT(23)
+#define LPC32XX_CLKPWR_INTSRC_USB_BIT          _BIT(22)
+#define LPC32XX_CLKPWR_INTSRC_I2C_BIT          _BIT(21)
+#define LPC32XX_CLKPWR_INTSRC_USBOTGTIMER_BIT  _BIT(20)
+#define LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT    _BIT(19)
+#define LPC32XX_CLKPWR_INTSRC_KEY_BIT          _BIT(16)
+#define LPC32XX_CLKPWR_INTSRC_MAC_BIT          _BIT(7)
+#define LPC32XX_CLKPWR_INTSRC_P0P1_BIT         _BIT(6)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_05_BIT      _BIT(5)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_04_BIT      _BIT(4)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_03_BIT      _BIT(3)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_02_BIT      _BIT(2)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_01_BIT      _BIT(1)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT      _BIT(0)
+
+/*
+ * clkpwr_start_pin, clkpwr_start_raw_sts_pin, clkpwr_start_sts_pin,
+ * clkpwr_start_pol_pin register bit definitions
+ */
+#define LPC32XX_CLKPWR_EXTSRC_U7_RX_BIT                _BIT(31)
+#define LPC32XX_CLKPWR_EXTSRC_U7_HCTS_BIT      _BIT(30)
+#define LPC32XX_CLKPWR_EXTSRC_U6_IRRX_BIT      _BIT(28)
+#define LPC32XX_CLKPWR_EXTSRC_U5_RX_BIT                _BIT(26)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT       _BIT(25)
+#define LPC32XX_CLKPWR_EXTSRC_U3_RX_BIT                _BIT(24)
+#define LPC32XX_CLKPWR_EXTSRC_U2_HCTS_BIT      _BIT(23)
+#define LPC32XX_CLKPWR_EXTSRC_U2_RX_BIT                _BIT(22)
+#define LPC32XX_CLKPWR_EXTSRC_U1_RX_BIT                _BIT(21)
+#define LPC32XX_CLKPWR_EXTSRC_MSDIO_INT_BIT    _BIT(18)
+#define LPC32XX_CLKPWR_EXTSRC_MSDIO_SRT_BIT    _BIT(17)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT       _BIT(16)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_05_BIT       _BIT(15)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_04_BIT       _BIT(14)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_03_BIT       _BIT(13)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_02_BIT       _BIT(12)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_01_BIT       _BIT(11)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_00_BIT       _BIT(10)
+#define LPC32XX_CLKPWR_EXTSRC_SYSCLKEN_BIT     _BIT(9)
+#define LPC32XX_CLKPWR_EXTSRC_SPI1_DATIN_BIT   _BIT(8)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_07_BIT       _BIT(7)
+#define LPC32XX_CLKPWR_EXTSRC_SPI2_DATIN_BIT   _BIT(6)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_19_BIT       _BIT(5)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_09_BIT       _BIT(4)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_08_BIT       _BIT(3)
+
+/*
+ * clkpwr_hclk_div register definitions
+ */
+#define LPC32XX_CLKPWR_HCLKDIV_DDRCLK_STOP     (0x0 << 7)
+#define LPC32XX_CLKPWR_HCLKDIV_DDRCLK_NORM     (0x1 << 7)
+#define LPC32XX_CLKPWR_HCLKDIV_DDRCLK_HALF     (0x2 << 7)
+#define LPC32XX_CLKPWR_HCLKDIV_PCLK_DIV(n)     (((n) & 0x1F) << 2)
+#define LPC32XX_CLKPWR_HCLKDIV_DIV_2POW(n)     ((n) & 0x3)
+
+/*
+ * clkpwr_pwr_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_CTRL_FORCE_PCLK         _BIT(10)
+#define LPC32XX_CLKPWR_SDRAM_SELF_RFSH         _BIT(9)
+#define LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH     _BIT(8)
+#define LPC32XX_CLKPWR_AUTO_SDRAM_SELF_RFSH    _BIT(7)
+#define LPC32XX_CLKPWR_HIGHCORE_STATE_BIT      _BIT(5)
+#define LPC32XX_CLKPWR_SYSCLKEN_STATE_BIT      _BIT(4)
+#define LPC32XX_CLKPWR_SYSCLKEN_GPIO_EN                _BIT(3)
+#define LPC32XX_CLKPWR_SELECT_RUN_MODE         _BIT(2)
+#define LPC32XX_CLKPWR_HIGHCORE_GPIO_EN                _BIT(1)
+#define LPC32XX_CLKPWR_STOP_MODE_CTRL          _BIT(0)
+
+/*
+ * clkpwr_pll397_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_PLL397_MSLOCK_STS       _BIT(10)
+#define LPC32XX_CLKPWR_PLL397_BYPASS           _BIT(9)
+#define LPC32XX_CLKPWR_PLL397_BIAS_NORM                0x000
+#define LPC32XX_CLKPWR_PLL397_BIAS_N12_5       0x040
+#define LPC32XX_CLKPWR_PLL397_BIAS_N25         0x080
+#define LPC32XX_CLKPWR_PLL397_BIAS_N37_5       0x0C0
+#define LPC32XX_CLKPWR_PLL397_BIAS_P12_5       0x100
+#define LPC32XX_CLKPWR_PLL397_BIAS_P25         0x140
+#define LPC32XX_CLKPWR_PLL397_BIAS_P37_5       0x180
+#define LPC32XX_CLKPWR_PLL397_BIAS_P50         0x1C0
+#define LPC32XX_CLKPWR_PLL397_BIAS_MASK                0x1C0
+#define LPC32XX_CLKPWR_SYSCTRL_PLL397_DIS      _BIT(1)
+#define LPC32XX_CLKPWR_SYSCTRL_PLL397_STS      _BIT(0)
+
+/*
+ * clkpwr_main_osc_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_MOSC_ADD_CAP(n)         (((n) & 0x7F) << 2)
+#define LPC32XX_CLKPWR_MOSC_CAP_MASK           (0x7F << 2)
+#define LPC32XX_CLKPWR_TEST_MODE               _BIT(1)
+#define LPC32XX_CLKPWR_MOSC_DISABLE            _BIT(0)
+
+/*
+ * clkpwr_sysclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SYSCTRL_BP_TRIG(n)      (((n) & 0x3FF) << 2)
+#define LPC32XX_CLKPWR_SYSCTRL_BP_MASK         (0x3FF << 2)
+#define LPC32XX_CLKPWR_SYSCTRL_USEPLL397       _BIT(1)
+#define LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX       _BIT(0)
+
+/*
+ * clkpwr_lcdclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT12   0x000
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16   0x040
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT15   0x080
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT24   0x0C0
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_STN4M   0x100
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_STN8C   0x140
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_DSTN4M  0x180
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_DSTN8C  0x1C0
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK     0x01C0
+#define LPC32XX_CLKPWR_LCDCTRL_CLK_EN          0x020
+#define LPC32XX_CLKPWR_LCDCTRL_SET_PSCALE(n)   ((n - 1) & 0x1F)
+#define LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK      0x001F
+
+/*
+ * clkpwr_hclkpll_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_HCLKPLL_POWER_UP                _BIT(16)
+#define LPC32XX_CLKPWR_HCLKPLL_CCO_BYPASS      _BIT(15)
+#define LPC32XX_CLKPWR_HCLKPLL_POSTDIV_BYPASS  _BIT(14)
+#define LPC32XX_CLKPWR_HCLKPLL_FDBK_SEL_FCLK   _BIT(13)
+#define LPC32XX_CLKPWR_HCLKPLL_POSTDIV_2POW(n) (((n) & 0x3) << 11)
+#define LPC32XX_CLKPWR_HCLKPLL_PREDIV_PLUS1(n) (((n) & 0x3) << 9)
+#define LPC32XX_CLKPWR_HCLKPLL_PLLM(n)         (((n) & 0xFF) << 1)
+#define LPC32XX_CLKPWR_HCLKPLL_PLL_STS         _BIT(0)
+
+/*
+ * clkpwr_adc_clk_ctrl_1 register definitions
+ */
+#define LPC32XX_CLKPWR_ADCCTRL1_RTDIV(n)       (((n) & 0xFF) << 0)
+#define LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL       _BIT(8)
+
+/*
+ * clkpwr_usb_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_USBCTRL_HCLK_EN         _BIT(24)
+#define LPC32XX_CLKPWR_USBCTRL_USBI2C_EN       _BIT(23)
+#define LPC32XX_CLKPWR_USBCTRL_USBDVND_EN      _BIT(22)
+#define LPC32XX_CLKPWR_USBCTRL_USBHSTND_EN     _BIT(21)
+#define LPC32XX_CLKPWR_USBCTRL_PU_ADD          (0x0 << 19)
+#define LPC32XX_CLKPWR_USBCTRL_BUS_KEEPER      (0x1 << 19)
+#define LPC32XX_CLKPWR_USBCTRL_PD_ADD          (0x3 << 19)
+#define LPC32XX_CLKPWR_USBCTRL_CLK_EN2         _BIT(18)
+#define LPC32XX_CLKPWR_USBCTRL_CLK_EN1         _BIT(17)
+#define LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP       _BIT(16)
+#define LPC32XX_CLKPWR_USBCTRL_CCO_BYPASS      _BIT(15)
+#define LPC32XX_CLKPWR_USBCTRL_POSTDIV_BYPASS  _BIT(14)
+#define LPC32XX_CLKPWR_USBCTRL_FDBK_SEL_FCLK   _BIT(13)
+#define LPC32XX_CLKPWR_USBCTRL_POSTDIV_2POW(n) (((n) & 0x3) << 11)
+#define LPC32XX_CLKPWR_USBCTRL_PREDIV_PLUS1(n) (((n) & 0x3) << 9)
+#define LPC32XX_CLKPWR_USBCTRL_FDBK_PLUS1(n)   (((n) & 0xFF) << 1)
+#define LPC32XX_CLKPWR_USBCTRL_PLL_STS         _BIT(0)
+
+/*
+ * clkpwr_sdramclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SDRCLK_FASTSLEW_CLK     _BIT(22)
+#define LPC32XX_CLKPWR_SDRCLK_FASTSLEW         _BIT(21)
+#define LPC32XX_CLKPWR_SDRCLK_FASTSLEW_DAT     _BIT(20)
+#define LPC32XX_CLKPWR_SDRCLK_SW_DDR_RESET     _BIT(19)
+#define LPC32XX_CLKPWR_SDRCLK_HCLK_DLY(n)      (((n) & 0x1F) << 14)
+#define LPC32XX_CLKPWR_SDRCLK_DLY_ADDR_STS     _BIT(13)
+#define LPC32XX_CLKPWR_SDRCLK_SENS_FACT(n)     (((n) & 0x7) << 10)
+#define LPC32XX_CLKPWR_SDRCLK_USE_CAL          _BIT(9)
+#define LPC32XX_CLKPWR_SDRCLK_DO_CAL           _BIT(8)
+#define LPC32XX_CLKPWR_SDRCLK_CAL_ON_RTC       _BIT(7)
+#define LPC32XX_CLKPWR_SDRCLK_DQS_DLY(n)       (((n) & 0x1F) << 2)
+#define LPC32XX_CLKPWR_SDRCLK_USE_DDR          _BIT(1)
+#define LPC32XX_CLKPWR_SDRCLK_CLK_DIS          _BIT(0)
+
+/*
+ * clkpwr_ssp_blk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP1RX      _BIT(5)
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP1TX      _BIT(4)
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP0RX      _BIT(3)
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP0TX      _BIT(2)
+#define LPC32XX_CLKPWR_SSPCTRL_SSPCLK1_EN      _BIT(1)
+#define LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN      _BIT(0)
+
+/*
+ * clkpwr_i2s_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_I2SCTRL_I2S1_RX_FOR_TX  _BIT(6)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S1_TX_FOR_RX  _BIT(5)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA    _BIT(4)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S0_RX_FOR_TX  _BIT(3)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S0_TX_FOR_RX  _BIT(2)
+#define LPC32XX_CLKPWR_I2SCTRL_I2SCLK1_EN      _BIT(1)
+#define LPC32XX_CLKPWR_I2SCTRL_I2SCLK0_EN      _BIT(0)
+
+/*
+ * clkpwr_ms_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_MSCARD_MSDIO_PIN_DIS    _BIT(10)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO_PU_EN      _BIT(9)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO23_DIS      _BIT(8)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO1_DIS       _BIT(7)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO0_DIS       _BIT(6)
+#define LPC32XX_CLKPWR_MSCARD_SDCARD_EN                _BIT(5)
+#define LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(n)    ((n) & 0xF)
+
+/*
+ * clkpwr_macclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_MACCTRL_NO_ENET_PIS     0x00
+#define LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS    0x08
+#define LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS   0x18
+#define LPC32XX_CLKPWR_MACCTRL_PINS_MSK                0x18
+#define LPC32XX_CLKPWR_MACCTRL_DMACLK_EN       _BIT(2)
+#define LPC32XX_CLKPWR_MACCTRL_MMIOCLK_EN      _BIT(1)
+#define LPC32XX_CLKPWR_MACCTRL_HRCCLK_EN       _BIT(0)
+
+/*
+ * clkpwr_test_clk_sel register definitions
+ */
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_PERCLK     (0x0 << 5)
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_RTC                (0x1 << 5)
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_MOSC       (0x2 << 5)
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_MASK       (0x3 << 5)
+#define LPC32XX_CLKPWR_TESTCLK_TESTCLK1_EN     _BIT(4)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_HCLK       (0x0 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_PERCLK     (0x1 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_USBCLK     (0x2 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC       (0x5 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_PLL397     (0x7 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_MASK       (0x7 << 1)
+#define LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN     _BIT(0)
+
+/*
+ * clkpwr_sw_int register definitions
+ */
+#define LPC32XX_CLKPWR_SW_INT(n)               (_BIT(0) | (((n) & 0x7F) << 1))
+#define LPC32XX_CLKPWR_SW_GET_ARG(n)           (((n) & 0xFE) >> 1)
+
+/*
+ * clkpwr_i2c_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE   _BIT(4)
+#define LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE     _BIT(3)
+#define LPC32XX_CLKPWR_I2CCLK_I2C1HI_DRIVE     _BIT(2)
+#define LPC32XX_CLKPWR_I2CCLK_I2C2CLK_EN       _BIT(1)
+#define LPC32XX_CLKPWR_I2CCLK_I2C1CLK_EN       _BIT(0)
+
+/*
+ * clkpwr_key_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_KEYCLKCTRL_CLK_EN       0x1
+
+/*
+ * clkpwr_adc_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN     0x1
+
+/*
+ * clkpwr_pwm_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_PWMCLK_PWM2_DIV(n)      (((n) & 0xF) << 8)
+#define LPC32XX_CLKPWR_PWMCLK_PWM1_DIV(n)      (((n) & 0xF) << 4)
+#define LPC32XX_CLKPWR_PWMCLK_PWM2SEL_PCLK     0x8
+#define LPC32XX_CLKPWR_PWMCLK_PWM2CLK_EN       0x4
+#define LPC32XX_CLKPWR_PWMCLK_PWM1SEL_PCLK     0x2
+#define LPC32XX_CLKPWR_PWMCLK_PWM1CLK_EN       0x1
+
+/*
+ * clkpwr_timer_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_PWMCLK_HSTIMER_EN       0x2
+#define LPC32XX_CLKPWR_PWMCLK_WDOG_EN          0x1
+
+/*
+ * clkpwr_timers_pwms_clk_ctrl_1 register definitions
+ */
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER3_EN     0x20
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER2_EN     0x10
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER1_EN     0x08
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER0_EN     0x04
+#define LPC32XX_CLKPWR_TMRPWMCLK_PWM4_EN       0x02
+#define LPC32XX_CLKPWR_TMRPWMCLK_PWM3_EN       0x01
+
+/*
+ * clkpwr_spi_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI2DATIO    0x80
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI2CLK      0x40
+#define LPC32XX_CLKPWR_SPICLK_USE_SPI2         0x20
+#define LPC32XX_CLKPWR_SPICLK_SPI2CLK_EN       0x10
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI1DATIO    0x08
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI1CLK      0x04
+#define LPC32XX_CLKPWR_SPICLK_USE_SPI1         0x02
+#define LPC32XX_CLKPWR_SPICLK_SPI1CLK_EN       0x01
+
+/*
+ * clkpwr_nand_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_NANDCLK_INTSEL_MLC      0x20
+#define LPC32XX_CLKPWR_NANDCLK_DMA_RNB         0x10
+#define LPC32XX_CLKPWR_NANDCLK_DMA_INT         0x08
+#define LPC32XX_CLKPWR_NANDCLK_SEL_SLC         0x04
+#define LPC32XX_CLKPWR_NANDCLK_MLCCLK_EN       0x02
+#define LPC32XX_CLKPWR_NANDCLK_SLCCLK_EN       0x01
+
+/*
+ * clkpwr_uart3_clk_ctrl, clkpwr_uart4_clk_ctrl, clkpwr_uart5_clk_ctrl
+ * and clkpwr_uart6_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_UART_Y_DIV(y)           ((y) & 0xFF)
+#define LPC32XX_CLKPWR_UART_X_DIV(x)           (((x) & 0xFF) << 8)
+#define LPC32XX_CLKPWR_UART_USE_HCLK           _BIT(16)
+
+/*
+ * clkpwr_irda_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_IRDA_Y_DIV(y)           ((y) & 0xFF)
+#define LPC32XX_CLKPWR_IRDA_X_DIV(x)           (((x) & 0xFF) << 8)
+
+/*
+ * clkpwr_uart_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART6_EN    _BIT(3)
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART5_EN    _BIT(2)
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART4_EN    _BIT(1)
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART3_EN    _BIT(0)
+
+/*
+ * clkpwr_dmaclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN       0x1
+
+/*
+ * clkpwr_autoclock register definitions
+ */
+#define LPC32XX_CLKPWR_AUTOCLK_USB_EN          0x40
+#define LPC32XX_CLKPWR_AUTOCLK_IRAM_EN         0x02
+#define LPC32XX_CLKPWR_AUTOCLK_IROM_EN         0x01
+
+/*
+ * Interrupt controller register offsets
+ */
+#define LPC32XX_INTC_MASK(x)                   io_p2v((x) + 0x00)
+#define LPC32XX_INTC_RAW_STAT(x)               io_p2v((x) + 0x04)
+#define LPC32XX_INTC_STAT(x)                   io_p2v((x) + 0x08)
+#define LPC32XX_INTC_POLAR(x)                  io_p2v((x) + 0x0C)
+#define LPC32XX_INTC_ACT_TYPE(x)               io_p2v((x) + 0x10)
+#define LPC32XX_INTC_TYPE(x)                   io_p2v((x) + 0x14)
+
+/*
+ * Timer/counter register offsets
+ */
+#define LCP32XX_TIMER_IR(x)                    io_p2v((x) + 0x00)
+#define LCP32XX_TIMER_TCR(x)                   io_p2v((x) + 0x04)
+#define LCP32XX_TIMER_TC(x)                    io_p2v((x) + 0x08)
+#define LCP32XX_TIMER_PR(x)                    io_p2v((x) + 0x0C)
+#define LCP32XX_TIMER_PC(x)                    io_p2v((x) + 0x10)
+#define LCP32XX_TIMER_MCR(x)                   io_p2v((x) + 0x14)
+#define LCP32XX_TIMER_MR0(x)                   io_p2v((x) + 0x18)
+#define LCP32XX_TIMER_MR1(x)                   io_p2v((x) + 0x1C)
+#define LCP32XX_TIMER_MR2(x)                   io_p2v((x) + 0x20)
+#define LCP32XX_TIMER_MR3(x)                   io_p2v((x) + 0x24)
+#define LCP32XX_TIMER_CCR(x)                   io_p2v((x) + 0x28)
+#define LCP32XX_TIMER_CR0(x)                   io_p2v((x) + 0x2C)
+#define LCP32XX_TIMER_CR1(x)                   io_p2v((x) + 0x30)
+#define LCP32XX_TIMER_CR2(x)                   io_p2v((x) + 0x34)
+#define LCP32XX_TIMER_CR3(x)                   io_p2v((x) + 0x38)
+#define LCP32XX_TIMER_EMR(x)                   io_p2v((x) + 0x3C)
+#define LCP32XX_TIMER_CTCR(x)                  io_p2v((x) + 0x70)
+
+/*
+ * ir register definitions
+ */
+#define LCP32XX_TIMER_CNTR_MTCH_BIT(n)         (1 << ((n) & 0x3))
+#define LCP32XX_TIMER_CNTR_CAPT_BIT(n)         (1 << (4 + ((n) & 0x3)))
+
+/*
+ * tcr register definitions
+ */
+#define LCP32XX_TIMER_CNTR_TCR_EN              0x1
+#define LCP32XX_TIMER_CNTR_TCR_RESET           0x2
+
+/*
+ * mcr register definitions
+ */
+#define LCP32XX_TIMER_CNTR_MCR_MTCH(n)         (0x1 << ((n) * 3))
+#define LCP32XX_TIMER_CNTR_MCR_RESET(n)                (0x1 << (((n) * 3) + 1))
+#define LCP32XX_TIMER_CNTR_MCR_STOP(n)         (0x1 << (((n) * 3) + 2))
+
+/*
+ * Standard UART register offsets
+ */
+#define LPC32XX_UART_DLL_FIFO(x)               io_p2v((x) + 0x00)
+#define LPC32XX_UART_DLM_IER(x)                        io_p2v((x) + 0x04)
+#define LPC32XX_UART_IIR_FCR(x)                        io_p2v((x) + 0x08)
+#define LPC32XX_UART_LCR(x)                    io_p2v((x) + 0x0C)
+#define LPC32XX_UART_MODEM_CTRL(x)             io_p2v((x) + 0x10)
+#define LPC32XX_UART_LSR(x)                    io_p2v((x) + 0x14)
+#define LPC32XX_UART_MODEM_STATUS(x)           io_p2v((x) + 0x18)
+#define LPC32XX_UART_RXLEV(x)                  io_p2v((x) + 0x1C)
+
+/*
+ * UART control structure offsets
+ */
+#define _UCREG(x)                              io_p2v(\
+                                               LPC32XX_UART_CTRL_BASE + (x))
+#define LPC32XX_UARTCTL_CTRL                   _UCREG(0x00)
+#define LPC32XX_UARTCTL_CLKMODE                        _UCREG(0x04)
+#define LPC32XX_UARTCTL_CLOOP                  _UCREG(0x08)
+
+/*
+ * ctrl register definitions
+ */
+#define LPC32XX_UART_U3_MD_CTRL_EN             _BIT(11)
+#define LPC32XX_UART_IRRX6_INV_EN              _BIT(10)
+#define LPC32XX_UART_HDPX_EN                   _BIT(9)
+#define LPC32XX_UART_UART6_IRDAMOD_BYPASS      _BIT(5)
+#define LPC32XX_RT_IRTX6_INV_EN                        _BIT(4)
+#define LPC32XX_RT_IRTX6_INV_MIR_EN            _BIT(3)
+#define LPC32XX_RT_RX_IRPULSE_3_16_115K                _BIT(2)
+#define LPC32XX_RT_TX_IRPULSE_3_16_115K                _BIT(1)
+#define LPC32XX_UART_U5_ROUTE_TO_USB           _BIT(0)
+
+/*
+ * clkmode register definitions
+ */
+#define LPC32XX_UART_ENABLED_CLOCKS(n)         (((n) >> 16) & 0x7F)
+#define LPC32XX_UART_ENABLED_CLOCK(n, u)       (((n) >> (16 + (u))) & 0x1)
+#define LPC32XX_UART_ENABLED_CLKS_ANY          _BIT(14)
+#define LPC32XX_UART_CLKMODE_OFF               0x0
+#define LPC32XX_UART_CLKMODE_ON                        0x1
+#define LPC32XX_UART_CLKMODE_AUTO              0x2
+#define LPC32XX_UART_CLKMODE_MASK(u)           (0x3 << ((((u) - 3) * 2) + 4))
+#define LPC32XX_UART_CLKMODE_LOAD(m, u)                ((m) << ((((u) - 3) * 2) + 4))
+
+/*
+ * GPIO Module Register offsets
+ */
+#define _GPREG(x)                              io_p2v(LPC32XX_GPIO_BASE + (x))
+#define LPC32XX_GPIO_P_MUX_SET                 _GPREG(0x100)
+#define LPC32XX_GPIO_P_MUX_CLR                 _GPREG(0x104)
+#define LPC32XX_GPIO_P_MUX_STATE               _GPREG(0x108)
+#define LPC32XX_GPIO_P3_MUX_SET                        _GPREG(0x110)
+#define LPC32XX_GPIO_P3_MUX_CLR                        _GPREG(0x114)
+#define LPC32XX_GPIO_P3_MUX_STATE              _GPREG(0x118)
+#define LPC32XX_GPIO_P0_MUX_SET                        _GPREG(0x120)
+#define LPC32XX_GPIO_P0_MUX_CLR                        _GPREG(0x124)
+#define LPC32XX_GPIO_P0_MUX_STATE              _GPREG(0x128)
+#define LPC32XX_GPIO_P1_MUX_SET                        _GPREG(0x130)
+#define LPC32XX_GPIO_P1_MUX_CLR                        _GPREG(0x134)
+#define LPC32XX_GPIO_P1_MUX_STATE              _GPREG(0x138)
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/system.h b/arch/arm/mach-lpc32xx/include/mach/system.h
new file mode 100644 (file)
index 0000000..df3b0de
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/system.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+static void arch_idle(void)
+{
+       cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+       extern void lpc32xx_watchdog_reset(void);
+
+       switch (mode) {
+       case 's':
+       case 'h':
+               printk(KERN_CRIT "RESET: Rebooting system\n");
+
+               /* Disable interrupts */
+               local_irq_disable();
+
+               lpc32xx_watchdog_reset();
+               break;
+
+       default:
+               /* Do nothing */
+               break;
+       }
+
+       /* Wait for watchdog to reset system */
+       while (1)
+               ;
+}
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/timex.h b/arch/arm/mach-lpc32xx/include/mach/timex.h
new file mode 100644 (file)
index 0000000..8d4066b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/timex.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/*
+ * Rate in Hz of the main system oscillator. This value should match
+ * the value 'MAIN_OSC_FREQ' in platform.h
+ */
+#define CLOCK_TICK_RATE        13000000
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/uncompress.h b/arch/arm/mach-lpc32xx/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..c142487
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/uncompress.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARM_ARCH_UNCOMPRESS_H
+#define __ASM_ARM_ARCH_UNCOMPRESS_H
+
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+/*
+ * Uncompress output is hardcoded to standard UART 5
+ */
+
+#define UART_FIFO_CTL_TX_RESET (1 << 2)
+#define UART_STATUS_TX_MT      (1 << 6)
+
+#define _UARTREG(x)            (void __iomem *)(LPC32XX_UART5_BASE + (x))
+
+#define LPC32XX_UART_DLLFIFO_O 0x00
+#define LPC32XX_UART_IIRFCR_O  0x08
+#define LPC32XX_UART_LSR_O     0x14
+
+static inline void putc(int ch)
+{
+       /* Wait for transmit FIFO to empty */
+       while ((__raw_readl(_UARTREG(LPC32XX_UART_LSR_O)) &
+               UART_STATUS_TX_MT) == 0)
+               ;
+
+       __raw_writel((u32) ch, _UARTREG(LPC32XX_UART_DLLFIFO_O));
+}
+
+static inline void flush(void)
+{
+       __raw_writel(__raw_readl(_UARTREG(LPC32XX_UART_IIRFCR_O)) |
+               UART_FIFO_CTL_TX_RESET, _UARTREG(LPC32XX_UART_IIRFCR_O));
+}
+
+/* NULL functions; we don't presently need them */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/vmalloc.h b/arch/arm/mach-lpc32xx/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..d1d936c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/vmalloc.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END    0xF0000000
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
new file mode 100644 (file)
index 0000000..bd0df26
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * arch/arm/mach-lpc32xx/irq.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+/*
+ * Default value representing the Activation polarity of all internal
+ * interrupt sources
+ */
+#define MIC_APR_DEFAULT                0x3FF0EFE0
+#define SIC1_APR_DEFAULT       0xFBD27186
+#define SIC2_APR_DEFAULT       0x801810C0
+
+/*
+ * Default value representing the Activation Type of all internal
+ * interrupt sources. All are level sensitive.
+ */
+#define MIC_ATR_DEFAULT                0x00000000
+#define SIC1_ATR_DEFAULT       0x00026000
+#define SIC2_ATR_DEFAULT       0x00000000
+
+struct lpc32xx_event_group_regs {
+       void __iomem *enab_reg;
+       void __iomem *edge_reg;
+       void __iomem *maskstat_reg;
+       void __iomem *rawstat_reg;
+};
+
+static const struct lpc32xx_event_group_regs lpc32xx_event_int_regs = {
+       .enab_reg = LPC32XX_CLKPWR_INT_ER,
+       .edge_reg = LPC32XX_CLKPWR_INT_AP,
+       .maskstat_reg = LPC32XX_CLKPWR_INT_SR,
+       .rawstat_reg = LPC32XX_CLKPWR_INT_RS,
+};
+
+static const struct lpc32xx_event_group_regs lpc32xx_event_pin_regs = {
+       .enab_reg = LPC32XX_CLKPWR_PIN_ER,
+       .edge_reg = LPC32XX_CLKPWR_PIN_AP,
+       .maskstat_reg = LPC32XX_CLKPWR_PIN_SR,
+       .rawstat_reg = LPC32XX_CLKPWR_PIN_RS,
+};
+
+struct lpc32xx_event_info {
+       const struct lpc32xx_event_group_regs *event_group;
+       u32 mask;
+};
+
+/*
+ * Maps an IRQ number to and event mask and register
+ */
+static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = {
+       [IRQ_LPC32XX_GPI_08] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_08_BIT,
+       },
+       [IRQ_LPC32XX_GPI_09] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_09_BIT,
+       },
+       [IRQ_LPC32XX_GPI_19] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_19_BIT,
+       },
+       [IRQ_LPC32XX_GPI_07] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_07_BIT,
+       },
+       [IRQ_LPC32XX_GPI_00] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_00_BIT,
+       },
+       [IRQ_LPC32XX_GPI_01] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_01_BIT,
+       },
+       [IRQ_LPC32XX_GPI_02] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_02_BIT,
+       },
+       [IRQ_LPC32XX_GPI_03] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_03_BIT,
+       },
+       [IRQ_LPC32XX_GPI_04] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_04_BIT,
+       },
+       [IRQ_LPC32XX_GPI_05] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_05_BIT,
+       },
+       [IRQ_LPC32XX_GPI_06] = {
+               .event_group = &lpc32xx_event_pin_regs,
+               .mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT,
+       },
+       [IRQ_LPC32XX_GPIO_00] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT,
+       },
+       [IRQ_LPC32XX_GPIO_01] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_GPIO_01_BIT,
+       },
+       [IRQ_LPC32XX_GPIO_02] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_GPIO_02_BIT,
+       },
+       [IRQ_LPC32XX_GPIO_03] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_GPIO_03_BIT,
+       },
+       [IRQ_LPC32XX_GPIO_04] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_GPIO_04_BIT,
+       },
+       [IRQ_LPC32XX_GPIO_05] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_GPIO_05_BIT,
+       },
+       [IRQ_LPC32XX_KEY] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_KEY_BIT,
+       },
+       [IRQ_LPC32XX_USB_OTG_ATX] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT,
+       },
+       [IRQ_LPC32XX_USB_HOST] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_USB_BIT,
+       },
+       [IRQ_LPC32XX_RTC] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_RTC_BIT,
+       },
+       [IRQ_LPC32XX_MSTIMER] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT,
+       },
+       [IRQ_LPC32XX_TS_AUX] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_TS_AUX_BIT,
+       },
+       [IRQ_LPC32XX_TS_P] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_TS_P_BIT,
+       },
+       [IRQ_LPC32XX_TS_IRQ] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_ADC_BIT,
+       },
+};
+
+static void get_controller(unsigned int irq, unsigned int *base,
+       unsigned int *irqbit)
+{
+       if (irq < 32) {
+               *base = LPC32XX_MIC_BASE;
+               *irqbit = 1 << irq;
+       } else if (irq < 64) {
+               *base = LPC32XX_SIC1_BASE;
+               *irqbit = 1 << (irq - 32);
+       } else {
+               *base = LPC32XX_SIC2_BASE;
+               *irqbit = 1 << (irq - 64);
+       }
+}
+
+static void lpc32xx_mask_irq(unsigned int irq)
+{
+       unsigned int reg, ctrl, mask;
+
+       get_controller(irq, &ctrl, &mask);
+
+       reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask;
+       __raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
+}
+
+static void lpc32xx_unmask_irq(unsigned int irq)
+{
+       unsigned int reg, ctrl, mask;
+
+       get_controller(irq, &ctrl, &mask);
+
+       reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask;
+       __raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
+}
+
+static void lpc32xx_ack_irq(unsigned int irq)
+{
+       unsigned int ctrl, mask;
+
+       get_controller(irq, &ctrl, &mask);
+
+       __raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl));
+
+       /* Also need to clear pending wake event */
+       if (lpc32xx_events[irq].mask != 0)
+               __raw_writel(lpc32xx_events[irq].mask,
+                       lpc32xx_events[irq].event_group->rawstat_reg);
+}
+
+static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
+       int use_edge)
+{
+       unsigned int reg, ctrl, mask;
+
+       get_controller(irq, &ctrl, &mask);
+
+       /* Activation level, high or low */
+       reg = __raw_readl(LPC32XX_INTC_POLAR(ctrl));
+       if (use_high_level)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       __raw_writel(reg, LPC32XX_INTC_POLAR(ctrl));
+
+       /* Activation type, edge or level */
+       reg = __raw_readl(LPC32XX_INTC_ACT_TYPE(ctrl));
+       if (use_edge)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       __raw_writel(reg, LPC32XX_INTC_ACT_TYPE(ctrl));
+
+       /* Use same polarity for the wake events */
+       if (lpc32xx_events[irq].mask != 0) {
+               reg = __raw_readl(lpc32xx_events[irq].event_group->edge_reg);
+
+               if (use_high_level)
+                       reg |= lpc32xx_events[irq].mask;
+               else
+                       reg &= ~lpc32xx_events[irq].mask;
+
+               __raw_writel(reg, lpc32xx_events[irq].event_group->edge_reg);
+       }
+}
+
+static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
+{
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               /* Rising edge sensitive */
+               __lpc32xx_set_irq_type(irq, 1, 1);
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               /* Falling edge sensitive */
+               __lpc32xx_set_irq_type(irq, 0, 1);
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               /* Low level sensitive */
+               __lpc32xx_set_irq_type(irq, 0, 0);
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               /* High level sensitive */
+               __lpc32xx_set_irq_type(irq, 1, 0);
+               break;
+
+       /* Other modes are not supported */
+       default:
+               return -EINVAL;
+       }
+
+       /* Ok to use the level handler for all types */
+       set_irq_handler(irq, handle_level_irq);
+
+       return 0;
+}
+
+static int lpc32xx_irq_wake(unsigned int irqno, unsigned int state)
+{
+       unsigned long eventreg;
+
+       if (lpc32xx_events[irqno].mask != 0) {
+               eventreg = __raw_readl(lpc32xx_events[irqno].
+                       event_group->enab_reg);
+
+               if (state)
+                       eventreg |= lpc32xx_events[irqno].mask;
+               else
+                       eventreg &= ~lpc32xx_events[irqno].mask;
+
+               __raw_writel(eventreg,
+                       lpc32xx_events[irqno].event_group->enab_reg);
+
+               return 0;
+       }
+
+       /* Clear event */
+       __raw_writel(lpc32xx_events[irqno].mask,
+               lpc32xx_events[irqno].event_group->rawstat_reg);
+
+       return -ENODEV;
+}
+
+static void __init lpc32xx_set_default_mappings(unsigned int apr,
+       unsigned int atr, unsigned int offset)
+{
+       unsigned int i;
+
+       /* Set activation levels for each interrupt */
+       i = 0;
+       while (i < 32) {
+               __lpc32xx_set_irq_type(offset + i, ((apr >> i) & 0x1),
+                       ((atr >> i) & 0x1));
+               i++;
+       }
+}
+
+static struct irq_chip lpc32xx_irq_chip = {
+       .ack = lpc32xx_ack_irq,
+       .mask = lpc32xx_mask_irq,
+       .unmask = lpc32xx_unmask_irq,
+       .set_type = lpc32xx_set_irq_type,
+       .set_wake = lpc32xx_irq_wake
+};
+
+static void lpc32xx_sic1_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned long ints = __raw_readl(LPC32XX_INTC_STAT(LPC32XX_SIC1_BASE));
+
+       while (ints != 0) {
+               int irqno = fls(ints) - 1;
+
+               ints &= ~(1 << irqno);
+
+               generic_handle_irq(LPC32XX_SIC1_IRQ(irqno));
+       }
+}
+
+static void lpc32xx_sic2_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned long ints = __raw_readl(LPC32XX_INTC_STAT(LPC32XX_SIC2_BASE));
+
+       while (ints != 0) {
+               int irqno = fls(ints) - 1;
+
+               ints &= ~(1 << irqno);
+
+               generic_handle_irq(LPC32XX_SIC2_IRQ(irqno));
+       }
+}
+
+void __init lpc32xx_init_irq(void)
+{
+       unsigned int i;
+
+       /* Setup MIC */
+       __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
+       __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_MIC_BASE));
+       __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_MIC_BASE));
+
+       /* Setup SIC1 */
+       __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE));
+       __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE));
+       __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE));
+
+       /* Setup SIC2 */
+       __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE));
+       __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE));
+       __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE));
+
+       /* Configure supported IRQ's */
+       for (i = 0; i < NR_IRQS; i++) {
+               set_irq_chip(i, &lpc32xx_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       /* Set default mappings */
+       lpc32xx_set_default_mappings(MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
+       lpc32xx_set_default_mappings(SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, 32);
+       lpc32xx_set_default_mappings(SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, 64);
+
+       /* mask all interrupts except SUBIRQ */
+       __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
+       __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE));
+       __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE));
+
+       /* MIC SUBIRQx interrupts will route handling to the chain handlers */
+       set_irq_chained_handler(IRQ_LPC32XX_SUB1IRQ, lpc32xx_sic1_handler);
+       set_irq_chained_handler(IRQ_LPC32XX_SUB2IRQ, lpc32xx_sic2_handler);
+
+       /* Initially disable all wake events */
+       __raw_writel(0, LPC32XX_CLKPWR_P01_ER);
+       __raw_writel(0, LPC32XX_CLKPWR_INT_ER);
+       __raw_writel(0, LPC32XX_CLKPWR_PIN_ER);
+
+       /*
+        * Default wake activation polarities, all pin sources are low edge
+        * triggered
+        */
+       __raw_writel(LPC32XX_CLKPWR_INTSRC_TS_P_BIT |
+               LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT |
+               LPC32XX_CLKPWR_INTSRC_RTC_BIT,
+               LPC32XX_CLKPWR_INT_AP);
+       __raw_writel(0, LPC32XX_CLKPWR_PIN_AP);
+
+       /* Clear latched wake event states */
+       __raw_writel(__raw_readl(LPC32XX_CLKPWR_PIN_RS),
+               LPC32XX_CLKPWR_PIN_RS);
+       __raw_writel(__raw_readl(LPC32XX_CLKPWR_INT_RS),
+               LPC32XX_CLKPWR_INT_RS);
+}
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
new file mode 100644 (file)
index 0000000..bc9a42d
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * arch/arm/mach-lpc32xx/phy3250.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/amba/pl022.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+/*
+ * Mapped GPIOLIB GPIOs
+ */
+#define SPI0_CS_GPIO   LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
+#define LCD_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
+#define BKL_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
+#define LED_GPIO       LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 1)
+
+/*
+ * AMBA LCD controller
+ */
+static struct clcd_panel conn_lcd_panel = {
+       .mode           = {
+               .name           = "QVGA portrait",
+               .refresh        = 60,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 191828,
+               .left_margin    = 22,
+               .right_margin   = 11,
+               .upper_margin   = 2,
+               .lower_margin   = 1,
+               .hsync_len      = 5,
+               .vsync_len      = 2,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = (TIM2_IVS | TIM2_IHS),
+       .cntl           = (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
+                               CNTL_LCDBPP16_565),
+       .bpp            = 16,
+};
+#define PANEL_SIZE (3 * SZ_64K)
+
+static int lpc32xx_clcd_setup(struct clcd_fb *fb)
+{
+       dma_addr_t dma;
+
+       fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+               PANEL_SIZE, &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 = PANEL_SIZE;
+       fb->panel = &conn_lcd_panel;
+
+       if (gpio_request(LCD_POWER_GPIO, "LCD power"))
+               printk(KERN_ERR "Error requesting gpio %u",
+                       LCD_POWER_GPIO);
+       else if (gpio_direction_output(LCD_POWER_GPIO, 1))
+               printk(KERN_ERR "Error setting gpio %u to output",
+                       LCD_POWER_GPIO);
+
+       if (gpio_request(BKL_POWER_GPIO, "LCD backlight power"))
+               printk(KERN_ERR "Error requesting gpio %u",
+                       BKL_POWER_GPIO);
+       else if (gpio_direction_output(BKL_POWER_GPIO, 1))
+               printk(KERN_ERR "Error setting gpio %u to output",
+                       BKL_POWER_GPIO);
+
+       return 0;
+}
+
+static int lpc32xx_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 lpc32xx_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);
+}
+
+/*
+ * On some early LCD modules (1307.0), the backlight logic is inverted.
+ * For those board variants, swap the disable and enable states for
+ * BKL_POWER_GPIO.
+*/
+static void clcd_disable(struct clcd_fb *fb)
+{
+       gpio_set_value(BKL_POWER_GPIO, 0);
+       gpio_set_value(LCD_POWER_GPIO, 0);
+}
+
+static void clcd_enable(struct clcd_fb *fb)
+{
+       gpio_set_value(BKL_POWER_GPIO, 1);
+       gpio_set_value(LCD_POWER_GPIO, 1);
+}
+
+static struct clcd_board lpc32xx_clcd_data = {
+       .name           = "Phytec LCD",
+       .check          = clcdfb_check,
+       .decode         = clcdfb_decode,
+       .disable        = clcd_disable,
+       .enable         = clcd_enable,
+       .setup          = lpc32xx_clcd_setup,
+       .mmap           = lpc32xx_clcd_mmap,
+       .remove         = lpc32xx_clcd_remove,
+};
+
+static struct amba_device lpc32xx_clcd_device = {
+       .dev                            = {
+               .coherent_dma_mask      = ~0,
+               .init_name              = "dev:clcd",
+               .platform_data          = &lpc32xx_clcd_data,
+       },
+       .res                            = {
+               .start                  = LPC32XX_LCD_BASE,
+               .end                    = (LPC32XX_LCD_BASE + SZ_4K - 1),
+               .flags                  = IORESOURCE_MEM,
+       },
+       .dma_mask                       = ~0,
+       .irq                            = {IRQ_LPC32XX_LCD, NO_IRQ},
+};
+
+/*
+ * AMBA SSP (SPI)
+ */
+static void phy3250_spi_cs_set(u32 control)
+{
+       gpio_set_value(SPI0_CS_GPIO, (int) control);
+}
+
+static struct pl022_config_chip spi0_chip_info = {
+       .lbm                    = LOOPBACK_DISABLED,
+       .com_mode               = INTERRUPT_TRANSFER,
+       .iface                  = SSP_INTERFACE_MOTOROLA_SPI,
+       .hierarchy              = SSP_MASTER,
+       .slave_tx_disable       = 0,
+       .endian_tx              = SSP_TX_LSB,
+       .endian_rx              = SSP_RX_LSB,
+       .data_size              = SSP_DATA_BITS_8,
+       .rx_lev_trig            = SSP_RX_4_OR_MORE_ELEM,
+       .tx_lev_trig            = SSP_TX_4_OR_MORE_EMPTY_LOC,
+       .clk_phase              = SSP_CLK_FIRST_EDGE,
+       .clk_pol                = SSP_CLK_POL_IDLE_LOW,
+       .ctrl_len               = SSP_BITS_8,
+       .wait_state             = SSP_MWIRE_WAIT_ZERO,
+       .duplex                 = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+       .cs_control             = phy3250_spi_cs_set,
+};
+
+static struct pl022_ssp_controller lpc32xx_ssp0_data = {
+       .bus_id                 = 0,
+       .num_chipselect         = 1,
+       .enable_dma             = 0,
+};
+
+static struct amba_device lpc32xx_ssp0_device = {
+       .dev                            = {
+               .coherent_dma_mask      = ~0,
+               .init_name              = "dev:ssp0",
+               .platform_data          = &lpc32xx_ssp0_data,
+       },
+       .res                            = {
+               .start                  = LPC32XX_SSP0_BASE,
+               .end                    = (LPC32XX_SSP0_BASE + SZ_4K - 1),
+               .flags                  = IORESOURCE_MEM,
+       },
+       .dma_mask                       = ~0,
+       .irq                            = {IRQ_LPC32XX_SSP0, NO_IRQ},
+};
+
+/* AT25 driver registration */
+static int __init phy3250_spi_board_register(void)
+{
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+       static struct spi_board_info info[] = {
+               {
+                       .modalias = "spidev",
+                       .max_speed_hz = 5000000,
+                       .bus_num = 0,
+                       .chip_select = 0,
+                       .controller_data = &spi0_chip_info,
+               },
+       };
+
+#else
+       static struct spi_eeprom eeprom = {
+               .name = "at25256a",
+               .byte_len = 0x8000,
+               .page_size = 64,
+               .flags = EE_ADDR2,
+       };
+
+       static struct spi_board_info info[] = {
+               {
+                       .modalias = "at25",
+                       .max_speed_hz = 5000000,
+                       .bus_num = 0,
+                       .chip_select = 0,
+                       .platform_data = &eeprom,
+                       .controller_data = &spi0_chip_info,
+               },
+       };
+#endif
+       return spi_register_board_info(info, ARRAY_SIZE(info));
+}
+arch_initcall(phy3250_spi_board_register);
+
+static struct i2c_board_info __initdata phy3250_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("pcf8563", 0x51),
+       },
+};
+
+static struct gpio_led phy_leds[] = {
+       {
+               .name                   = "led0",
+               .gpio                   = LED_GPIO,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",
+       },
+};
+
+static struct gpio_led_platform_data led_data = {
+       .leds = phy_leds,
+       .num_leds = ARRAY_SIZE(phy_leds),
+};
+
+static struct platform_device lpc32xx_gpio_led_device = {
+       .name                   = "leds-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &led_data,
+};
+
+static struct platform_device *phy3250_devs[] __initdata = {
+       &lpc32xx_i2c0_device,
+       &lpc32xx_i2c1_device,
+       &lpc32xx_i2c2_device,
+       &lpc32xx_watchdog_device,
+       &lpc32xx_gpio_led_device,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+       &lpc32xx_clcd_device,
+       &lpc32xx_ssp0_device,
+};
+
+/*
+ * Board specific functions
+ */
+static void __init phy3250_board_init(void)
+{
+       u32 tmp;
+       int i;
+
+       lpc32xx_gpio_init();
+
+       /* Register GPIOs used on this board */
+       if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
+               printk(KERN_ERR "Error requesting gpio %u",
+                       SPI0_CS_GPIO);
+       else if (gpio_direction_output(SPI0_CS_GPIO, 1))
+               printk(KERN_ERR "Error setting gpio %u to output",
+                       SPI0_CS_GPIO);
+
+       /* Setup network interface for RMII mode */
+       tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
+       tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
+       tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
+       __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
+
+       /* Setup SLC NAND controller muxing */
+       __raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
+               LPC32XX_CLKPWR_NAND_CLK_CTRL);
+
+       /* Setup LCD muxing to RGB565 */
+       tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL) &
+               ~(LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK |
+               LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK);
+       tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16;
+       __raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+       /* Set up I2C pull levels */
+       tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
+       tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE |
+               LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE;
+       __raw_writel(tmp, LPC32XX_CLKPWR_I2C_CLK_CTRL);
+
+       /* Disable IrDA pulsing support on UART6 */
+       tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
+       tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
+       __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
+
+       /* Enable DMA for I2S1 channel */
+       tmp = __raw_readl(LPC32XX_CLKPWR_I2S_CLK_CTRL);
+       tmp = LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA;
+       __raw_writel(tmp, LPC32XX_CLKPWR_I2S_CLK_CTRL);
+
+       lpc32xx_serial_init();
+
+       /*
+        * AMBA peripheral clocks need to be enabled prior to AMBA device
+        * detection or a data fault will occur, so enable the clocks
+        * here. However, we don't want to enable them if the peripheral
+        * isn't included in the image
+        */
+#ifdef CONFIG_FB_ARMCLCD
+       tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
+       __raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN),
+               LPC32XX_CLKPWR_LCDCLK_CTRL);
+#endif
+#ifdef CONFIG_SPI_PL022
+       tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL);
+       __raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN),
+               LPC32XX_CLKPWR_SSP_CLK_CTRL);
+#endif
+
+       platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs));
+       for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+               struct amba_device *d = amba_devs[i];
+               amba_device_register(d, &iomem_resource);
+       }
+
+       /* Test clock needed for UDA1380 initial init */
+       __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
+               LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
+               LPC32XX_CLKPWR_TEST_CLK_SEL);
+
+       i2c_register_board_info(0, phy3250_i2c_board_info,
+               ARRAY_SIZE(phy3250_i2c_board_info));
+}
+
+static int __init lpc32xx_display_uid(void)
+{
+       u32 uid[4];
+
+       lpc32xx_get_uid(uid);
+
+       printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
+               uid[3], uid[2], uid[1], uid[0]);
+
+       return 1;
+}
+arch_initcall(lpc32xx_display_uid);
+
+MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
+       /* Maintainer: Kevin Wells, NXP Semiconductors */
+       .phys_io        = LPC32XX_UART5_BASE,
+       .io_pg_offst    = ((IO_ADDRESS(LPC32XX_UART5_BASE))>>18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = lpc32xx_map_io,
+       .init_irq       = lpc32xx_init_irq,
+       .timer          = &lpc32xx_timer,
+       .init_machine   = phy3250_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c
new file mode 100644 (file)
index 0000000..a6e2aed
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * arch/arm/mach-lpc32xx/pm.c
+ *
+ * Original authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
+ * Modified by Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+/*
+ * LPC32XX CPU and system power management
+ *
+ * The LCP32XX has three CPU modes for controlling system power: run,
+ * direct-run, and halt modes. When switching between halt and run modes,
+ * the CPU transistions through direct-run mode. For Linux, direct-run
+ * mode is not used in normal operation. Halt mode is used when the
+ * system is fully suspended.
+ *
+ * Run mode:
+ * The ARM CPU clock (HCLK_PLL), HCLK bus clock, and PCLK bus clocks are
+ * derived from the HCLK PLL. The HCLK and PCLK bus rates are divided from
+ * the HCLK_PLL rate. Linux runs in this mode.
+ *
+ * Direct-run mode:
+ * The ARM CPU clock, HCLK bus clock, and PCLK bus clocks are driven from
+ * SYSCLK. SYSCLK is usually around 13MHz, but may vary based on SYSCLK
+ * source or the frequency of the main oscillator. In this mode, the
+ * HCLK_PLL can be safely enabled, changed, or disabled.
+ *
+ * Halt mode:
+ * SYSCLK is gated off and the CPU and system clocks are halted.
+ * Peripherals based on the 32KHz oscillator clock (ie, RTC, touch,
+ * key scanner, etc.) still operate if enabled. In this state, an enabled
+ * system event (ie, GPIO state change, RTC match, key press, etc.) will
+ * wake the system up back into direct-run mode.
+ *
+ * DRAM refresh
+ * DRAM clocking and refresh are slightly different for systems with DDR
+ * DRAM or regular SDRAM devices. If SDRAM is used in the system, the
+ * SDRAM will still be accessible in direct-run mode. In DDR based systems,
+ * a transistion to direct-run mode will stop all DDR accesses (no clocks).
+ * Because of this, the code to switch power modes and the code to enter
+ * and exit DRAM self-refresh modes must not be executed in DRAM. A small
+ * section of IRAM is used instead for this.
+ *
+ * Suspend is handled with the following logic:
+ *  Backup a small area of IRAM used for the suspend code
+ *  Copy suspend code to IRAM
+ *  Transfer control to code in IRAM
+ *  Places DRAMs in self-refresh mode
+ *  Enter direct-run mode
+ *  Save state of HCLK_PLL PLL
+ *  Disable HCLK_PLL PLL
+ *  Enter halt mode - CPU and buses will stop
+ *  System enters direct-run mode when an enabled event occurs
+ *  HCLK PLL state is restored
+ *  Run mode is entered
+ *  DRAMS are placed back into normal mode
+ *  Code execution returns from IRAM
+ *  IRAM code are used for suspend is restored
+ *  Suspend mode is exited
+ */
+
+#include <linux/suspend.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+#include "clock.h"
+
+#define TEMP_IRAM_AREA  IO_ADDRESS(LPC32XX_IRAM_BASE)
+
+/*
+ * Both STANDBY and MEM suspend states are handled the same with no
+ * loss of CPU or memory state
+ */
+static int lpc32xx_pm_enter(suspend_state_t state)
+{
+       int (*lpc32xx_suspend_ptr) (void);
+       void *iram_swap_area;
+
+       /* Allocate some space for temporary IRAM storage */
+       iram_swap_area = kmalloc(lpc32xx_sys_suspend_sz, GFP_KERNEL);
+       if (!iram_swap_area) {
+               printk(KERN_ERR
+                      "PM Suspend: cannot allocate memory to save portion "
+                       "of SRAM\n");
+               return -ENOMEM;
+       }
+
+       /* Backup a small area of IRAM used for the suspend code */
+       memcpy(iram_swap_area, (void *) TEMP_IRAM_AREA,
+               lpc32xx_sys_suspend_sz);
+
+       /*
+        * Copy code to suspend system into IRAM. The suspend code
+        * needs to run from IRAM as DRAM may no longer be available
+        * when the PLL is stopped.
+        */
+       memcpy((void *) TEMP_IRAM_AREA, &lpc32xx_sys_suspend,
+               lpc32xx_sys_suspend_sz);
+       flush_icache_range((unsigned long)TEMP_IRAM_AREA,
+               (unsigned long)(TEMP_IRAM_AREA) + lpc32xx_sys_suspend_sz);
+
+       /* Transfer to suspend code in IRAM */
+       lpc32xx_suspend_ptr = (void *) TEMP_IRAM_AREA;
+       flush_cache_all();
+       (void) lpc32xx_suspend_ptr();
+
+       /* Restore original IRAM contents */
+       memcpy((void *) TEMP_IRAM_AREA, iram_swap_area,
+               lpc32xx_sys_suspend_sz);
+
+       kfree(iram_swap_area);
+
+       return 0;
+}
+
+static struct platform_suspend_ops lpc32xx_pm_ops = {
+       .valid  = suspend_valid_only_mem,
+       .enter  = lpc32xx_pm_enter,
+};
+
+#define EMC_DYN_MEM_CTRL_OFS 0x20
+#define EMC_SRMMC           (1 << 3)
+#define EMC_CTRL_REG io_p2v(LPC32XX_EMC_BASE + EMC_DYN_MEM_CTRL_OFS)
+static int __init lpc32xx_pm_init(void)
+{
+       /*
+        * Setup SDRAM self-refresh clock to automatically disable o
+        * start of self-refresh. This only needs to be done once.
+        */
+       __raw_writel(__raw_readl(EMC_CTRL_REG) | EMC_SRMMC, EMC_CTRL_REG);
+
+       suspend_set_ops(&lpc32xx_pm_ops);
+
+       return 0;
+}
+arch_initcall(lpc32xx_pm_init);
diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c
new file mode 100644 (file)
index 0000000..429cfdb
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * arch/arm/mach-lpc32xx/serial.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+#define LPC32XX_SUART_FIFO_SIZE        64
+
+/* Standard 8250/16550 compatible serial ports */
+static struct plat_serial8250_port serial_std_platform_data[] = {
+#ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT
+       {
+               .membase        = io_p2v(LPC32XX_UART5_BASE),
+               .mapbase        = LPC32XX_UART5_BASE,
+               .irq            = IRQ_LPC32XX_UART_IIR5,
+               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM32,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+                                       UPF_SKIP_TEST,
+       },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
+       {
+               .membase        = io_p2v(LPC32XX_UART3_BASE),
+               .mapbase        = LPC32XX_UART3_BASE,
+               .irq            = IRQ_LPC32XX_UART_IIR3,
+               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM32,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+                                       UPF_SKIP_TEST,
+       },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
+       {
+               .membase        = io_p2v(LPC32XX_UART4_BASE),
+               .mapbase        = LPC32XX_UART4_BASE,
+               .irq            = IRQ_LPC32XX_UART_IIR4,
+               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM32,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+                                       UPF_SKIP_TEST,
+       },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
+       {
+               .membase        = io_p2v(LPC32XX_UART6_BASE),
+               .mapbase        = LPC32XX_UART6_BASE,
+               .irq            = IRQ_LPC32XX_UART_IIR6,
+               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
+               .regshift       = 2,
+               .iotype         = UPIO_MEM32,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+                                       UPF_SKIP_TEST,
+       },
+#endif
+       { },
+};
+
+struct uartinit {
+       char *uart_ck_name;
+       u32 ck_mode_mask;
+       void __iomem *pdiv_clk_reg;
+};
+
+static struct uartinit uartinit_data[] __initdata = {
+#ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT
+       {
+               .uart_ck_name = "uart5_ck",
+               .ck_mode_mask =
+                       LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
+               .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
+       },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
+       {
+               .uart_ck_name = "uart3_ck",
+               .ck_mode_mask =
+                       LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
+               .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
+       },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
+       {
+               .uart_ck_name = "uart4_ck",
+               .ck_mode_mask =
+                       LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
+               .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
+       },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
+       {
+               .uart_ck_name = "uart6_ck",
+               .ck_mode_mask =
+                       LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
+               .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
+       },
+#endif
+};
+
+static struct platform_device serial_std_platform_device = {
+       .name                   = "serial8250",
+       .id                     = 0,
+       .dev                    = {
+               .platform_data  = serial_std_platform_data,
+       },
+};
+
+static struct platform_device *lpc32xx_serial_devs[] __initdata = {
+       &serial_std_platform_device,
+};
+
+void __init lpc32xx_serial_init(void)
+{
+       u32 tmp, clkmodes = 0;
+       struct clk *clk;
+       unsigned int puart;
+       int i, j;
+
+       /* UART clocks are off, let clock driver manage them */
+       __raw_writel(0, LPC32XX_CLKPWR_UART_CLK_CTRL);
+
+       for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
+               clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
+               if (!IS_ERR(clk)) {
+                       clk_enable(clk);
+                       serial_std_platform_data[i].uartclk =
+                               clk_get_rate(clk);
+               }
+
+               /* Fall back on main osc rate if clock rate return fails */
+               if (serial_std_platform_data[i].uartclk == 0)
+                       serial_std_platform_data[i].uartclk =
+                               LPC32XX_MAIN_OSC_FREQ;
+
+               /* Setup UART clock modes for all UARTs, disable autoclock */
+               clkmodes |= uartinit_data[i].ck_mode_mask;
+
+               /* pre-UART clock divider set to 1 */
+               __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
+       }
+
+       /* This needs to be done after all UART clocks are setup */
+       __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
+       for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
+               /* Force a flush of the RX FIFOs to work around a HW bug */
+               puart = serial_std_platform_data[i].mapbase;
+               __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
+               __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
+               j = LPC32XX_SUART_FIFO_SIZE;
+               while (j--)
+                       tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart));
+               __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
+       }
+
+       /* Disable UART5->USB transparent mode or USB won't work */
+       tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
+       tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
+       __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
+
+       platform_add_devices(lpc32xx_serial_devs,
+               ARRAY_SIZE(lpc32xx_serial_devs));
+}
diff --git a/arch/arm/mach-lpc32xx/suspend.S b/arch/arm/mach-lpc32xx/suspend.S
new file mode 100644 (file)
index 0000000..374f9f0
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * arch/arm/mach-lpc32xx/suspend.S
+ *
+ * Original authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com>
+ * Modified by Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/* Using named register defines makes the code easier to follow */
+#define WORK1_REG                      r0
+#define WORK2_REG                      r1
+#define SAVED_HCLK_DIV_REG             r2
+#define SAVED_HCLK_PLL_REG             r3
+#define SAVED_DRAM_CLKCTRL_REG         r4
+#define SAVED_PWR_CTRL_REG             r5
+#define CLKPWRBASE_REG                 r6
+#define EMCBASE_REG                    r7
+
+#define LPC32XX_EMC_STATUS_OFFS                0x04
+#define LPC32XX_EMC_STATUS_BUSY                0x1
+#define LPC32XX_EMC_STATUS_SELF_RFSH   0x4
+
+#define LPC32XX_CLKPWR_PWR_CTRL_OFFS   0x44
+#define LPC32XX_CLKPWR_HCLK_DIV_OFFS   0x40
+#define LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS 0x58
+
+#define CLKPWR_PCLK_DIV_MASK           0xFFFFFE7F
+
+       .text
+
+ENTRY(lpc32xx_sys_suspend)
+       @ Save a copy of the used registers in IRAM, r0 is corrupted
+       adr     r0, tmp_stack_end
+       stmfd   r0!, {r3 - r7, sp, lr}
+
+       @ Load a few common register addresses
+       adr     WORK1_REG, reg_bases
+       ldr     CLKPWRBASE_REG, [WORK1_REG, #0]
+       ldr     EMCBASE_REG, [WORK1_REG, #4]
+
+       ldr     SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+       orr     WORK1_REG, SAVED_PWR_CTRL_REG, #LPC32XX_CLKPWR_SDRAM_SELF_RFSH
+
+       @ Wait for SDRAM busy status to go busy and then idle
+       @ This guarantees a small windows where DRAM isn't busy
+1:
+       ldr     WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+       and     WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+       cmp     WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+       bne     1b @ Branch while idle
+2:
+       ldr     WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+       and     WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+       cmp     WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+       beq     2b @ Branch until idle
+
+       @ Setup self-refresh with support for manual exit of
+       @ self-refresh mode
+       str     WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+       orr     WORK2_REG, WORK1_REG, #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
+       str     WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+       str     WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+       @ Wait for self-refresh acknowledge, clocks to the DRAM device
+       @ will automatically stop on start of self-refresh
+3:
+       ldr     WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+       and     WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
+       cmp     WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
+       bne     3b @ Branch until self-refresh mode starts
+
+       @ Enter direct-run mode from run mode
+       bic     WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_SELECT_RUN_MODE
+       str     WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+       @ Safe disable of DRAM clock in EMC block, prevents DDR sync
+       @ issues on restart
+       ldr     SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
+       and     WORK2_REG, SAVED_HCLK_DIV_REG, #CLKPWR_PCLK_DIV_MASK
+       str     WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
+
+       @ Save HCLK PLL state and disable HCLK PLL
+       ldr     SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+       bic     WORK2_REG, SAVED_HCLK_PLL_REG, #LPC32XX_CLKPWR_HCLKPLL_POWER_UP
+       str     WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+
+       @ Enter stop mode until an enabled event occurs
+       orr     WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
+       str     WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+       .rept 9
+       nop
+       .endr
+
+       @ Clear stop status
+       bic     WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
+
+       @ Restore original HCLK PLL value and wait for PLL lock
+       str     SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+4:
+       ldr     WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+       and     WORK2_REG, WORK2_REG, #LPC32XX_CLKPWR_HCLKPLL_PLL_STS
+       bne     4b
+
+       @ Re-enter run mode with self-refresh flag cleared, but no DRAM
+       @ update yet. DRAM is still in self-refresh
+       str     SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+       @ Restore original DRAM clock mode to restore DRAM clocks
+       str     SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
+
+       @ Clear self-refresh mode
+       orr     WORK1_REG, SAVED_PWR_CTRL_REG,\
+               #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
+       str     WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+       str     SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
+               #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+       @ Wait for EMC to clear self-refresh mode
+5:
+       ldr     WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+       and     WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
+       bne     5b @ Branch until self-refresh has exited
+
+       @ restore regs and return
+       adr     r0, tmp_stack
+       ldmfd   r0!, {r3 - r7, sp, pc}
+
+reg_bases:
+       .long   IO_ADDRESS(LPC32XX_CLK_PM_BASE)
+       .long   IO_ADDRESS(LPC32XX_EMC_BASE)
+
+tmp_stack:
+       .long   0, 0, 0, 0, 0, 0, 0
+tmp_stack_end:
+
+ENTRY(lpc32xx_sys_suspend_sz)
+       .word   . - lpc32xx_sys_suspend
diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c
new file mode 100644 (file)
index 0000000..630dd4a
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * arch/arm/mach-lpc32xx/timer.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2009 - 2010 NXP Semiconductors
+ * Copyright (C) 2009 Fontys University of Applied Sciences, Eindhoven
+ *                    Ed Schouten <e.schouten@fontys.nl>
+ *                    Laurens Timmermans <l.timmermans@fontys.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/clockchips.h>
+
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+static cycle_t lpc32xx_clksrc_read(struct clocksource *cs)
+{
+       return (cycle_t)__raw_readl(LCP32XX_TIMER_TC(LPC32XX_TIMER1_BASE));
+}
+
+static struct clocksource lpc32xx_clksrc = {
+       .name   = "lpc32xx_clksrc",
+       .shift  = 24,
+       .rating = 300,
+       .read   = lpc32xx_clksrc_read,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int lpc32xx_clkevt_next_event(unsigned long delta,
+    struct clock_event_device *dev)
+{
+       __raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
+               LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+       __raw_writel(delta, LCP32XX_TIMER_PR(LPC32XX_TIMER0_BASE));
+       __raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
+               LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+
+       return 0;
+}
+
+static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
+    struct clock_event_device *dev)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               WARN_ON(1);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /*
+                * Disable the timer. When using oneshot, we must also
+                * disable the timer to wait for the first call to
+                * set_next_event().
+                */
+               __raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static struct clock_event_device lpc32xx_clkevt = {
+       .name           = "lpc32xx_clkevt",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .rating         = 300,
+       .set_next_event = lpc32xx_clkevt_next_event,
+       .set_mode       = lpc32xx_clkevt_mode,
+};
+
+static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &lpc32xx_clkevt;
+
+       /* Clear match */
+       __raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
+               LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction lpc32xx_timer_irq = {
+       .name           = "LPC32XX Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = lpc32xx_timer_interrupt,
+};
+
+/*
+ * The clock management driver isn't initialized at this point, so the
+ * clocks need to be enabled here manually and then tagged as used in
+ * the clock driver initialization
+ */
+static void __init lpc32xx_timer_init(void)
+{
+       u32 clkrate, pllreg;
+
+       /* Enable timer clock */
+       __raw_writel(LPC32XX_CLKPWR_TMRPWMCLK_TIMER0_EN |
+               LPC32XX_CLKPWR_TMRPWMCLK_TIMER1_EN,
+               LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1);
+
+       /*
+        * The clock driver isn't initialized at this point. So determine if
+        * the SYSCLK is driven from the PLL397 or main oscillator and then use
+        * it to compute the PLL frequency and the PCLK divider to get the base
+        * timer rates. This rate is needed to compute the tick rate.
+        */
+       if (clk_is_sysclk_mainosc() != 0)
+               clkrate = LPC32XX_MAIN_OSC_FREQ;
+       else
+               clkrate = 397 * LPC32XX_CLOCK_OSC_FREQ;
+
+       /* Get ARM HCLKPLL register and convert it into a frequency */
+       pllreg = __raw_readl(LPC32XX_CLKPWR_HCLKPLL_CTRL) & 0x1FFFF;
+       clkrate = clk_get_pllrate_from_reg(clkrate, pllreg);
+
+       /* Get PCLK divider and divide ARM PLL clock by it to get timer rate */
+       clkrate = clkrate / clk_get_pclk_div();
+
+       /* Initial timer setup */
+       __raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+       __raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
+               LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+       __raw_writel(1, LCP32XX_TIMER_MR0(LPC32XX_TIMER0_BASE));
+       __raw_writel(LCP32XX_TIMER_CNTR_MCR_MTCH(0) |
+               LCP32XX_TIMER_CNTR_MCR_STOP(0) |
+               LCP32XX_TIMER_CNTR_MCR_RESET(0),
+               LCP32XX_TIMER_MCR(LPC32XX_TIMER0_BASE));
+
+       /* Setup tick interrupt */
+       setup_irq(IRQ_LPC32XX_TIMER0, &lpc32xx_timer_irq);
+
+       /* Setup the clockevent structure. */
+       lpc32xx_clkevt.mult = div_sc(clkrate, NSEC_PER_SEC,
+               lpc32xx_clkevt.shift);
+       lpc32xx_clkevt.max_delta_ns = clockevent_delta2ns(-1,
+               &lpc32xx_clkevt);
+       lpc32xx_clkevt.min_delta_ns = clockevent_delta2ns(1,
+               &lpc32xx_clkevt) + 1;
+       lpc32xx_clkevt.cpumask = cpumask_of(0);
+       clockevents_register_device(&lpc32xx_clkevt);
+
+       /* Use timer1 as clock source. */
+       __raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
+               LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+       __raw_writel(0, LCP32XX_TIMER_PR(LPC32XX_TIMER1_BASE));
+       __raw_writel(0, LCP32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
+       __raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
+               LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+       lpc32xx_clksrc.mult = clocksource_hz2mult(clkrate,
+               lpc32xx_clksrc.shift);
+       clocksource_register(&lpc32xx_clksrc);
+}
+
+struct sys_timer lpc32xx_timer = {
+       .init           = &lpc32xx_timer_init,
+};
+
index 66677f0acaed287fb5bde8b48f054334af195703..7ff8020d4d2422f0f509e7bb8aec2631dca60f72 100644 (file)
@@ -15,7 +15,7 @@ obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o devices-msm7x00.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o devices-msm7x00.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
 obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
new file mode 100644 (file)
index 0000000..523d213
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * linux/arch/arm/mach-msm/gpio.c
+ *
+ * Copyright (C) 2005 HP Labs
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2009 Pavel Machek <pavel@ucw.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include "board-trout.h"
+
+struct msm_gpio_chip {
+       struct gpio_chip        chip;
+       void __iomem            *reg;   /* Base of register bank */
+       u8                      shadow;
+};
+
+#define to_msm_gpio_chip(c) container_of(c, struct msm_gpio_chip, chip)
+
+static int msm_gpiolib_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
+       unsigned mask = 1 << offset;
+
+       return !!(readb(msm_gpio->reg) & mask);
+}
+
+static void msm_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+       struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
+       unsigned mask = 1 << offset;
+
+       if (val)
+               msm_gpio->shadow |= mask;
+       else
+               msm_gpio->shadow &= ~mask;
+
+       writeb(msm_gpio->shadow, msm_gpio->reg);
+}
+
+static int msm_gpiolib_direction_input(struct gpio_chip *chip,
+                                       unsigned offset)
+{
+       msm_gpiolib_set(chip, offset, 0);
+       return 0;
+}
+
+static int msm_gpiolib_direction_output(struct gpio_chip *chip,
+                                        unsigned offset, int val)
+{
+       msm_gpiolib_set(chip, offset, val);
+       return 0;
+}
+
+#define TROUT_GPIO_BANK(name, reg_num, base_gpio, shadow_val)          \
+       {                                                               \
+               .chip = {                                               \
+                       .label            = name,                       \
+                       .direction_input  = msm_gpiolib_direction_input,\
+                       .direction_output = msm_gpiolib_direction_output, \
+                       .get              = msm_gpiolib_get,            \
+                       .set              = msm_gpiolib_set,            \
+                       .base             = base_gpio,                  \
+                       .ngpio            = 8,                          \
+               },                                                      \
+               .reg = (void *) reg_num + TROUT_CPLD_BASE,              \
+               .shadow = shadow_val,                                   \
+       }
+
+static struct msm_gpio_chip msm_gpio_banks[] = {
+#if defined(CONFIG_MSM_DEBUG_UART1)
+       /* H2W pins <-> UART1 */
+       TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x40),
+#else
+       /* H2W pins <-> UART3, Bluetooth <-> UART1 */
+       TROUT_GPIO_BANK("MISC2", 0x00,   TROUT_GPIO_MISC2_BASE, 0x80),
+#endif
+       /* I2C pull */
+       TROUT_GPIO_BANK("MISC3", 0x02,   TROUT_GPIO_MISC3_BASE, 0x04),
+       TROUT_GPIO_BANK("MISC4", 0x04,   TROUT_GPIO_MISC4_BASE, 0),
+       /* mmdi 32k en */
+       TROUT_GPIO_BANK("MISC5", 0x06,   TROUT_GPIO_MISC5_BASE, 0x04),
+       TROUT_GPIO_BANK("INT2", 0x08,    TROUT_GPIO_INT2_BASE,  0),
+       TROUT_GPIO_BANK("MISC1", 0x0a,   TROUT_GPIO_MISC1_BASE, 0),
+       TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
+};
+
+/*
+ * Called from the processor-specific init to enable GPIO pin support.
+ */
+int __init trout_init_gpio(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
+               gpiochip_add(&msm_gpio_banks[i].chip);
+
+       return 0;
+}
+
+postcore_initcall(trout_init_gpio);
+
index dca5a5f062dce229fe98b9e00fe5f18e5ff40620..e69a1502e4e8dc80cac9dd620497b5adddd0e6d4 100644 (file)
@@ -50,7 +50,6 @@ static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
 {
        mi->nr_banks = 1;
        mi->bank[0].start = PHYS_OFFSET;
-       mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
        mi->bank[0].size = (101*1024*1024);
 }
 
index 4f345a5a0a61c7a0cd223a996e07b8650cddd52a..651851c3e1dd14d21ef24c497667dbe2f5d5828d 100644 (file)
@@ -1,5 +1,162 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+** Author: Brian Swetland <swetland@google.com>
+*/
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE           0x00000000
+#define MSM_SMI_SIZE           0x00800000
+
+#define MSM_EBI_BASE           0x10000000
+#define MSM_EBI_SIZE           0x06e00000
+
+#define MSM_PMEM_GPU0_BASE     0x00000000
+#define MSM_PMEM_GPU0_SIZE     0x00700000
+
+#define MSM_PMEM_MDP_BASE      0x02000000
+#define MSM_PMEM_MDP_SIZE      0x00800000
+
+#define MSM_PMEM_ADSP_BASE      0x02800000
+#define MSM_PMEM_ADSP_SIZE     0x00800000
+
+#define MSM_PMEM_CAMERA_BASE   0x03000000
+#define MSM_PMEM_CAMERA_SIZE   0x00800000
+
+#define MSM_FB_BASE            0x03800000
+#define MSM_FB_SIZE            0x00100000
+
+#define MSM_LINUX_BASE         MSM_EBI_BASE
+#define MSM_LINUX_SIZE         0x06500000
+
+#define MSM_PMEM_GPU1_SIZE     0x800000
+#define MSM_PMEM_GPU1_BASE     (MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE)
+
+#define MSM_RAM_CONSOLE_BASE   (MSM_EBI_BASE + 0x6d00000)
+#define MSM_RAM_CONSOLE_SIZE   (128 * SZ_1K)
+
+#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+#define TROUT_4_BALL_UP_0     1
+#define TROUT_4_BALL_LEFT_0   18
+#define TROUT_4_BALL_DOWN_0   57
+#define TROUT_4_BALL_RIGHT_0  91
+
+#define TROUT_5_BALL_UP_0     94
+#define TROUT_5_BALL_LEFT_0   18
+#define TROUT_5_BALL_DOWN_0   90
+#define TROUT_5_BALL_RIGHT_0  19
+
+#define TROUT_POWER_KEY     20
+
+#define TROUT_4_TP_LS_EN    19
+#define TROUT_5_TP_LS_EN    1
 
 #define TROUT_CPLD_BASE   0xE8100000
 #define TROUT_CPLD_START  0x98000000
 #define TROUT_CPLD_SIZE   SZ_4K
 
+#define TROUT_GPIO_CABLE_IN1           (83)
+#define TROUT_GPIO_CABLE_IN2           (49)
+
+#define TROUT_GPIO_START (128)
+
+#define TROUT_GPIO_INT_MASK0_REG            (0x0c)
+#define TROUT_GPIO_INT_STAT0_REG            (0x0e)
+#define TROUT_GPIO_INT_MASK1_REG            (0x14)
+#define TROUT_GPIO_INT_STAT1_REG            (0x10)
+
+#define TROUT_GPIO_HAPTIC_PWM               (28)
+#define TROUT_GPIO_PS_HOLD                  (25)
+
+#define TROUT_GPIO_MISC2_BASE               (TROUT_GPIO_START + 0x00)
+#define TROUT_GPIO_MISC3_BASE               (TROUT_GPIO_START + 0x08)
+#define TROUT_GPIO_MISC4_BASE               (TROUT_GPIO_START + 0x10)
+#define TROUT_GPIO_MISC5_BASE               (TROUT_GPIO_START + 0x18)
+#define TROUT_GPIO_INT2_BASE                (TROUT_GPIO_START + 0x20)
+#define TROUT_GPIO_MISC1_BASE               (TROUT_GPIO_START + 0x28)
+#define TROUT_GPIO_VIRTUAL_BASE             (TROUT_GPIO_START + 0x30)
+#define TROUT_GPIO_INT5_BASE                (TROUT_GPIO_START + 0x48)
+
+#define TROUT_GPIO_CHARGER_EN               (TROUT_GPIO_MISC2_BASE + 0)
+#define TROUT_GPIO_ISET                     (TROUT_GPIO_MISC2_BASE + 1)
+#define TROUT_GPIO_H2W_DAT_DIR              (TROUT_GPIO_MISC2_BASE + 2)
+#define TROUT_GPIO_H2W_CLK_DIR              (TROUT_GPIO_MISC2_BASE + 3)
+#define TROUT_GPIO_H2W_DAT_GPO              (TROUT_GPIO_MISC2_BASE + 4)
+#define TROUT_GPIO_H2W_CLK_GPO              (TROUT_GPIO_MISC2_BASE + 5)
+#define TROUT_GPIO_H2W_SEL0                 (TROUT_GPIO_MISC2_BASE + 6)
+#define TROUT_GPIO_H2W_SEL1                 (TROUT_GPIO_MISC2_BASE + 7)
+
+#define TROUT_GPIO_SPOTLIGHT_EN             (TROUT_GPIO_MISC3_BASE + 0)
+#define TROUT_GPIO_FLASH_EN                 (TROUT_GPIO_MISC3_BASE + 1)
+#define TROUT_GPIO_I2C_PULL                 (TROUT_GPIO_MISC3_BASE + 2)
+#define TROUT_GPIO_TP_I2C_PULL              (TROUT_GPIO_MISC3_BASE + 3)
+#define TROUT_GPIO_TP_EN                    (TROUT_GPIO_MISC3_BASE + 4)
+#define TROUT_GPIO_JOG_EN                   (TROUT_GPIO_MISC3_BASE + 5)
+#define TROUT_GPIO_UI_LED_EN                (TROUT_GPIO_MISC3_BASE + 6)
+#define TROUT_GPIO_QTKEY_LED_EN             (TROUT_GPIO_MISC3_BASE + 7)
+
+#define TROUT_GPIO_VCM_PWDN                 (TROUT_GPIO_MISC4_BASE + 0)
+#define TROUT_GPIO_USB_H2W_SW               (TROUT_GPIO_MISC4_BASE + 1)
+#define TROUT_GPIO_COMPASS_RST_N            (TROUT_GPIO_MISC4_BASE + 2)
+#define TROUT_GPIO_HAPTIC_EN_UP             (TROUT_GPIO_MISC4_BASE + 3)
+#define TROUT_GPIO_HAPTIC_EN_MAIN           (TROUT_GPIO_MISC4_BASE + 4)
+#define TROUT_GPIO_USB_PHY_RST_N            (TROUT_GPIO_MISC4_BASE + 5)
+#define TROUT_GPIO_WIFI_PA_RESETX           (TROUT_GPIO_MISC4_BASE + 6)
+#define TROUT_GPIO_WIFI_EN                  (TROUT_GPIO_MISC4_BASE + 7)
+
+#define TROUT_GPIO_BT_32K_EN                (TROUT_GPIO_MISC5_BASE + 0)
+#define TROUT_GPIO_MAC_32K_EN               (TROUT_GPIO_MISC5_BASE + 1)
+#define TROUT_GPIO_MDDI_32K_EN              (TROUT_GPIO_MISC5_BASE + 2)
+#define TROUT_GPIO_COMPASS_32K_EN           (TROUT_GPIO_MISC5_BASE + 3)
+
+#define TROUT_GPIO_NAVI_ACT_N               (TROUT_GPIO_INT2_BASE + 0)
+#define TROUT_GPIO_COMPASS_IRQ              (TROUT_GPIO_INT2_BASE + 1)
+#define TROUT_GPIO_SLIDING_DET              (TROUT_GPIO_INT2_BASE + 2)
+#define TROUT_GPIO_AUD_HSMIC_DET_N          (TROUT_GPIO_INT2_BASE + 3)
+#define TROUT_GPIO_SD_DOOR_N                (TROUT_GPIO_INT2_BASE + 4)
+#define TROUT_GPIO_CAM_BTN_STEP1_N          (TROUT_GPIO_INT2_BASE + 5)
+#define TROUT_GPIO_CAM_BTN_STEP2_N          (TROUT_GPIO_INT2_BASE + 6)
+#define TROUT_GPIO_TP_ATT_N                 (TROUT_GPIO_INT2_BASE + 7)
+#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE   (TROUT_GPIO_NAVI_ACT_N)
+#define TROUT_GPIO_BANK0_LAST_INT_SOURCE    (TROUT_GPIO_TP_ATT_N)
+
+#define TROUT_GPIO_H2W_DAT_GPI              (TROUT_GPIO_MISC1_BASE + 0)
+#define TROUT_GPIO_H2W_CLK_GPI              (TROUT_GPIO_MISC1_BASE + 1)
+#define TROUT_GPIO_CPLD128_VER_0            (TROUT_GPIO_MISC1_BASE + 4)
+#define TROUT_GPIO_CPLD128_VER_1            (TROUT_GPIO_MISC1_BASE + 5)
+#define TROUT_GPIO_CPLD128_VER_2            (TROUT_GPIO_MISC1_BASE + 6)
+#define TROUT_GPIO_CPLD128_VER_3            (TROUT_GPIO_MISC1_BASE + 7)
+
+#define TROUT_GPIO_SDMC_CD_N                (TROUT_GPIO_VIRTUAL_BASE + 0)
+#define TROUT_GPIO_END                      (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE   (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_LAST_INT_SOURCE    (TROUT_GPIO_SDMC_CD_N)
+
+#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \
+       (TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE)
+
+#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS)
+#define TROUT_INT_BANK0_COUNT (8)
+#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_BANK1_COUNT (1)
+#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \
+                       TROUT_INT_BANK1_COUNT - 1)
+#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \
+       (TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \
+       (TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n)))
+
+#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7))
+#define TROUT_BANK_TO_MASK_REG(bank) \
+       (bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG)
+#define TROUT_BANK_TO_STAT_REG(bank) \
+       (bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG)
+
+#endif /* GUARD */
index 262b441b4374a94dd71e90cc9ed1ce1d3b230d90..83e47c0d5c2e451de5f459653053684beb786ee8 100644 (file)
 #ifndef __ASM_ARCH_MSM_GPIO_H
 #define __ASM_ARCH_MSM_GPIO_H
 
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value  __gpio_get_value
+#define gpio_set_value  __gpio_set_value
+#define gpio_cansleep   __gpio_cansleep
+#define gpio_to_irq     __gpio_to_irq
+
 /**
  * struct msm_gpio - GPIO pin description
  * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
diff --git a/arch/arm/mach-mx1/Kconfig b/arch/arm/mach-mx1/Kconfig
deleted file mode 100644 (file)
index eb7660f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-if ARCH_MX1
-
-comment "MX1 platforms:"
-
-config MACH_MXLADS
-       bool
-
-config ARCH_MX1ADS
-       bool "MX1ADS platform"
-       select MACH_MXLADS
-       help
-         Say Y here if you are using Motorola MX1ADS/MXLADS boards
-
-config MACH_SCB9328
-       bool "Synertronixx scb9328"
-       help
-         Say Y here if you are using a Synertronixx scb9328 board
-
-endif
diff --git a/arch/arm/mach-mx1/Makefile b/arch/arm/mach-mx1/Makefile
deleted file mode 100644 (file)
index fc2ddf8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-EXTRA_CFLAGS += -DIMX_NEEDS_DEPRECATED_SYMBOLS
-obj-y                  += generic.o clock.o devices.o
-
-# Support for CMOS sensor interface
-obj-$(CONFIG_MX1_VIDEO)        += ksym_mx1.o mx1_camera_fiq.o
-
-# Specific board support
-obj-$(CONFIG_ARCH_MX1ADS) += mach-mx1ads.o
-obj-$(CONFIG_MACH_SCB9328) += mach-scb9328.o
diff --git a/arch/arm/mach-mx1/Makefile.boot b/arch/arm/mach-mx1/Makefile.boot
deleted file mode 100644 (file)
index 8ed1492..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-   zreladdr-y  := 0x08008000
-params_phys-y  := 0x08000100
-initrd_phys-y  := 0x08800000
-
diff --git a/arch/arm/mach-mx1/crm_regs.h b/arch/arm/mach-mx1/crm_regs.h
deleted file mode 100644 (file)
index 22e866f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-
-#ifndef __ARCH_ARM_MACH_MX1_CRM_REGS_H__
-#define __ARCH_ARM_MACH_MX1_CRM_REGS_H__
-
-#define CCM_BASE       IO_ADDRESS(CCM_BASE_ADDR)
-#define SCM_BASE       IO_ADDRESS(SCM_BASE_ADDR)
-
-/* CCM register addresses */
-#define CCM_CSCR       (CCM_BASE + 0x0)
-#define CCM_MPCTL0     (CCM_BASE + 0x4)
-#define CCM_MPCTL1     (CCM_BASE + 0x8)
-#define CCM_SPCTL0     (CCM_BASE + 0xC)
-#define CCM_SPCTL1     (CCM_BASE + 0x10)
-#define CCM_PCDR       (CCM_BASE + 0x20)
-
-#define CCM_CSCR_CLKO_OFFSET   29
-#define CCM_CSCR_CLKO_MASK     (0x7 << 29)
-#define CCM_CSCR_USB_OFFSET    26
-#define CCM_CSCR_USB_MASK      (0x7 << 26)
-#define CCM_CSCR_SPLL_RESTART  (1 << 22)
-#define CCM_CSCR_MPLL_RESTART  (1 << 21)
-#define CCM_CSCR_OSC_EN_SHIFT  17
-#define CCM_CSCR_SYSTEM_SEL    (1 << 16)
-#define CCM_CSCR_BCLK_OFFSET   10
-#define CCM_CSCR_BCLK_MASK     (0xF << 10)
-#define CCM_CSCR_PRESC         (1 << 15)
-#define CCM_CSCR_SPEN          (1 << 1)
-#define CCM_CSCR_MPEN          (1 << 0)
-
-#define CCM_PCDR_PCLK3_OFFSET  16
-#define CCM_PCDR_PCLK3_MASK    (0x7F << 16)
-#define CCM_PCDR_PCLK2_OFFSET  4
-#define CCM_PCDR_PCLK2_MASK    (0xF << 4)
-#define CCM_PCDR_PCLK1_OFFSET  0
-#define CCM_PCDR_PCLK1_MASK    0xF
-
-/* SCM register addresses */
-#define SCM_SIDR       (SCM_BASE + 0x0)
-#define SCM_FMCR       (SCM_BASE + 0x4)
-#define SCM_GPCR       (SCM_BASE + 0x8)
-#define SCM_GCCR       (SCM_BASE + 0xC)
-
-#define SCM_GCCR_DMA_CLK_EN_OFFSET     3
-#define SCM_GCCR_CSI_CLK_EN_OFFSET     2
-#define SCM_GCCR_MMA_CLK_EN_OFFSET     1
-#define SCM_GCCR_USBD_CLK_EN_OFFSET    0
-
-#endif /* __ARCH_ARM_MACH_MX2_CRM_REGS_H__ */
diff --git a/arch/arm/mach-mx1/devices.c b/arch/arm/mach-mx1/devices.c
deleted file mode 100644 (file)
index b6be29d..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
- * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- * Copyright (c) 2008 Darius Augulis <darius.augulis@teltonika.lt>
- *
- * This program is free software; 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/platform_device.h>
-#include <linux/gpio.h>
-#include <mach/irqs.h>
-#include <mach/hardware.h>
-
-#include "devices.h"
-
-static struct resource imx_csi_resources[] = {
-       {
-               .start  = 0x00224000,
-               .end    = 0x00224010,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = CSI_INT,
-               .end    = CSI_INT,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static u64 imx_csi_dmamask = 0xffffffffUL;
-
-struct platform_device imx_csi_device = {
-       .name           = "mx1-camera",
-       .id             = 0, /* This is used to put cameras on this interface */
-       .dev            = {
-               .dma_mask = &imx_csi_dmamask,
-               .coherent_dma_mask = 0xffffffff,
-       },
-       .resource       = imx_csi_resources,
-       .num_resources  = ARRAY_SIZE(imx_csi_resources),
-};
-
-static struct resource imx_i2c_resources[] = {
-       {
-               .start  = 0x00217000,
-               .end    = 0x00217010,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = I2C_INT,
-               .end    = I2C_INT,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_i2c_device = {
-       .name           = "imx-i2c",
-       .id             = 0,
-       .resource       = imx_i2c_resources,
-       .num_resources  = ARRAY_SIZE(imx_i2c_resources),
-};
-
-static struct resource imx_uart1_resources[] = {
-       {
-               .start  = UART1_BASE_ADDR,
-               .end    = UART1_BASE_ADDR + 0xD0,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = UART1_MINT_RX,
-               .end    = UART1_MINT_RX,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = UART1_MINT_TX,
-               .end    = UART1_MINT_TX,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = UART1_MINT_RTS,
-               .end    = UART1_MINT_RTS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_uart1_device = {
-       .name           = "imx-uart",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(imx_uart1_resources),
-       .resource       = imx_uart1_resources,
-};
-
-static struct resource imx_uart2_resources[] = {
-       {
-               .start  = UART2_BASE_ADDR,
-               .end    = UART2_BASE_ADDR + 0xD0,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = UART2_MINT_RX,
-               .end    = UART2_MINT_RX,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = UART2_MINT_TX,
-               .end    = UART2_MINT_TX,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = UART2_MINT_RTS,
-               .end    = UART2_MINT_RTS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_uart2_device = {
-       .name           = "imx-uart",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(imx_uart2_resources),
-       .resource       = imx_uart2_resources,
-};
-
-static struct resource imx_rtc_resources[] = {
-       {
-               .start  = 0x00204000,
-               .end    = 0x00204024,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = RTC_INT,
-               .end    = RTC_INT,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = RTC_SAMINT,
-               .end    = RTC_SAMINT,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_rtc_device = {
-       .name           = "rtc-imx",
-       .id             = 0,
-       .resource       = imx_rtc_resources,
-       .num_resources  = ARRAY_SIZE(imx_rtc_resources),
-};
-
-static struct resource imx_wdt_resources[] = {
-       {
-               .start  = 0x00201000,
-               .end    = 0x00201008,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = WDT_INT,
-               .end    = WDT_INT,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_wdt_device = {
-       .name           = "imx-wdt",
-       .id             = 0,
-       .resource       = imx_wdt_resources,
-       .num_resources  = ARRAY_SIZE(imx_wdt_resources),
-};
-
-static struct resource imx_usb_resources[] = {
-       {
-               .start  = 0x00212000,
-               .end    = 0x00212148,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = USBD_INT0,
-               .end    = USBD_INT0,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = USBD_INT1,
-               .end    = USBD_INT1,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = USBD_INT2,
-               .end    = USBD_INT2,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = USBD_INT3,
-               .end    = USBD_INT3,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = USBD_INT4,
-               .end    = USBD_INT4,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = USBD_INT5,
-               .end    = USBD_INT5,
-               .flags  = IORESOURCE_IRQ,
-       }, {
-               .start  = USBD_INT6,
-               .end    = USBD_INT6,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_usb_device = {
-       .name           = "imx_udc",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(imx_usb_resources),
-       .resource       = imx_usb_resources,
-};
-
-/* GPIO port description */
-static struct mxc_gpio_port imx_gpio_ports[] = {
-       {
-               .chip.label = "gpio-0",
-               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR),
-               .irq = GPIO_INT_PORTA,
-               .virtual_irq_start = MXC_GPIO_IRQ_START,
-       }, {
-               .chip.label = "gpio-1",
-               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x100),
-               .irq = GPIO_INT_PORTB,
-               .virtual_irq_start = MXC_GPIO_IRQ_START + 32,
-       }, {
-               .chip.label = "gpio-2",
-               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x200),
-               .irq = GPIO_INT_PORTC,
-               .virtual_irq_start = MXC_GPIO_IRQ_START + 64,
-       }, {
-               .chip.label = "gpio-3",
-               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x300),
-               .irq = GPIO_INT_PORTD,
-               .virtual_irq_start = MXC_GPIO_IRQ_START + 96,
-       }
-};
-
-int __init mxc_register_gpios(void)
-{
-       return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
-}
diff --git a/arch/arm/mach-mx1/devices.h b/arch/arm/mach-mx1/devices.h
deleted file mode 100644 (file)
index 0da5d7c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-extern struct platform_device imx_csi_device;
-extern struct platform_device imx_i2c_device;
-extern struct platform_device imx_uart1_device;
-extern struct platform_device imx_uart2_device;
-extern struct platform_device imx_rtc_device;
-extern struct platform_device imx_wdt_device;
-extern struct platform_device imx_usb_device;
diff --git a/arch/arm/mach-mx2/serial.c b/arch/arm/mach-mx2/serial.c
deleted file mode 100644 (file)
index 1c0c835..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Juergen Beisert, kernel@pengutronix.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., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <mach/hardware.h>
-#include <mach/imx-uart.h>
-#include "devices.h"
-
-static struct resource uart0[] = {
-       {
-               .start = MX2x_UART1_BASE_ADDR,
-               .end = MX2x_UART1_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX2x_INT_UART1,
-               .end = MX2x_INT_UART1,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device0 = {
-       .name = "imx-uart",
-       .id = 0,
-       .resource = uart0,
-       .num_resources = ARRAY_SIZE(uart0),
-};
-
-static struct resource uart1[] = {
-       {
-               .start = MX2x_UART2_BASE_ADDR,
-               .end = MX2x_UART2_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX2x_INT_UART2,
-               .end = MX2x_INT_UART2,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device1 = {
-       .name = "imx-uart",
-       .id = 1,
-       .resource = uart1,
-       .num_resources = ARRAY_SIZE(uart1),
-};
-
-static struct resource uart2[] = {
-       {
-               .start = MX2x_UART3_BASE_ADDR,
-               .end = MX2x_UART3_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX2x_INT_UART3,
-               .end = MX2x_INT_UART3,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device2 = {
-       .name = "imx-uart",
-       .id = 2,
-       .resource = uart2,
-       .num_resources = ARRAY_SIZE(uart2),
-};
-
-static struct resource uart3[] = {
-       {
-               .start = MX2x_UART4_BASE_ADDR,
-               .end = MX2x_UART4_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX2x_INT_UART4,
-               .end = MX2x_INT_UART4,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device3 = {
-       .name = "imx-uart",
-       .id = 3,
-       .resource = uart3,
-       .num_resources = ARRAY_SIZE(uart3),
-};
-
-#ifdef CONFIG_MACH_MX27
-static struct resource uart4[] = {
-       {
-               .start = MX27_UART5_BASE_ADDR,
-               .end = MX27_UART5_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX27_INT_UART5,
-               .end = MX27_INT_UART5,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device4 = {
-       .name = "imx-uart",
-       .id = 4,
-       .resource = uart4,
-       .num_resources = ARRAY_SIZE(uart4),
-};
-
-static struct resource uart5[] = {
-       {
-               .start = MX27_UART6_BASE_ADDR,
-               .end = MX27_UART6_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX27_INT_UART6,
-               .end = MX27_INT_UART6,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device5 = {
-       .name = "imx-uart",
-       .id = 5,
-       .resource = uart5,
-       .num_resources = ARRAY_SIZE(uart5),
-};
-#endif
index 54d217314ee9a3b57030af0f26f747d4d834e828..c71a7bc19284bf64b14f939f3094bfc501631240 100644 (file)
@@ -4,5 +4,28 @@ comment "MX25 platforms:"
 
 config MACH_MX25_3DS
        bool "Support MX25PDK (3DS) Platform"
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+
+config MACH_EUKREA_CPUIMX25
+       bool "Support Eukrea CPUIMX25 Platform"
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select MXC_ULPI if USB_ULPI
+
+choice
+       prompt "Baseboard"
+       depends on MACH_EUKREA_CPUIMX25
+       default MACH_EUKREA_MBIMXSD25_BASEBOARD
+
+config MACH_EUKREA_MBIMXSD25_BASEBOARD
+       prompt "Eukrea MBIMXSD development board"
+       bool
+       help
+         This adds board specific devices that can be found on Eukrea's
+         MBIMXSD evaluation board.
+
+endchoice
 
 endif
index 10cebc5ced8c0a0e15748fd7027effbee446d3f2..d9e46ce00a4ec747d92a47041ed98bebdeb3aa34 100644 (file)
@@ -1,3 +1,5 @@
 obj-y                          := mm.o devices.o
 obj-$(CONFIG_ARCH_MX25)                += clock.o
-obj-$(CONFIG_MACH_MX25_3DS)    += mach-mx25pdk.o
+obj-$(CONFIG_MACH_MX25_3DS)    += mach-mx25_3ds.o
+obj-$(CONFIG_MACH_EUKREA_CPUIMX25)             += mach-cpuimx25.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD)  += eukrea_mbimxsd-baseboard.o
index 155014993b13cc18d7724ca5d3d03604c7a103e1..40c7cc41cee372c906e3339f5da50f9e709f36df 100644 (file)
@@ -109,6 +109,16 @@ static unsigned long get_rate_uart(struct clk *clk)
        return get_rate_per(15);
 }
 
+static unsigned long get_rate_ssi2(struct clk *clk)
+{
+       return get_rate_per(14);
+}
+
+static unsigned long get_rate_ssi1(struct clk *clk)
+{
+       return get_rate_per(13);
+}
+
 static unsigned long get_rate_i2c(struct clk *clk)
 {
        return get_rate_per(6);
@@ -129,9 +139,17 @@ static unsigned long get_rate_lcdc(struct clk *clk)
        return get_rate_per(7);
 }
 
+static unsigned long get_rate_csi(struct clk *clk)
+{
+       return get_rate_per(0);
+}
+
 static unsigned long get_rate_otg(struct clk *clk)
 {
-       return 48000000; /* FIXME */
+       unsigned long cctl = readl(CRM_BASE + CCM_CCTL);
+       unsigned long rate = get_rate_upll();
+
+       return (cctl & (1 << 23)) ? 0 : rate / ((0x3F & (cctl >> 16)) + 1);
 }
 
 static int clk_cgcr_enable(struct clk *clk)
@@ -166,14 +184,40 @@ static void clk_cgcr_disable(struct clk *clk)
                .secondary      = s,                    \
        }
 
+/*
+ * Note: the following IPG clock gating bits are wrongly marked "Reserved" in
+ * the i.MX25 Reference Manual Rev 1, table 15-13. The information below is
+ * taken from the Freescale released BSP.
+ *
+ * bit reg     offset  clock
+ *
+ * 0   CGCR1   0       AUDMUX
+ * 12  CGCR1   12      ESAI
+ * 16  CGCR1   16      GPIO1
+ * 17  CGCR1   17      GPIO2
+ * 18  CGCR1   18      GPIO3
+ * 23  CGCR1   23      I2C1
+ * 24  CGCR1   24      I2C2
+ * 25  CGCR1   25      I2C3
+ * 27  CGCR1   27      IOMUXC
+ * 28  CGCR1   28      KPP
+ * 30  CGCR1   30      OWIRE
+ * 36  CGCR2   4       RTIC
+ * 51  CGCR2   19      WDOG
+ */
+
 DEFINE_CLOCK(gpt_clk,    0, CCM_CGCR0,  5, get_rate_gpt, NULL, NULL);
 DEFINE_CLOCK(uart_per_clk, 0, CCM_CGCR0, 15, get_rate_uart, NULL, NULL);
+DEFINE_CLOCK(ssi1_per_clk, 0, CCM_CGCR0, 13, get_rate_ipg, NULL, NULL);
+DEFINE_CLOCK(ssi2_per_clk, 0, CCM_CGCR0, 14, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi1_clk,  0, CCM_CGCR1,  5, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi2_clk,  0, CCM_CGCR1,  6, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi3_clk,  0, CCM_CGCR1,  7, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL,       NULL, NULL);
 DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL,      NULL, NULL);
 DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0,  7, NULL,      NULL, &lcdc_ahb_clk);
+DEFINE_CLOCK(csi_ahb_clk, 0, CCM_CGCR0, 18, get_rate_csi, NULL, NULL);
+DEFINE_CLOCK(csi_per_clk, 0, CCM_CGCR0, 0, get_rate_csi, NULL, &csi_ahb_clk);
 DEFINE_CLOCK(uart1_clk,  0, CCM_CGCR2, 14, get_rate_uart, NULL, &uart_per_clk);
 DEFINE_CLOCK(uart2_clk,  0, CCM_CGCR2, 15, get_rate_uart, NULL, &uart_per_clk);
 DEFINE_CLOCK(uart3_clk,  0, CCM_CGCR2, 16, get_rate_uart, NULL, &uart_per_clk);
@@ -191,6 +235,13 @@ DEFINE_CLOCK(i2c_clk,       0, CCM_CGCR0,  6, get_rate_i2c, NULL, NULL);
 DEFINE_CLOCK(fec_clk,   0, CCM_CGCR1, 15, get_rate_ipg, NULL, &fec_ahb_clk);
 DEFINE_CLOCK(dryice_clk, 0, CCM_CGCR1,  8, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(lcdc_clk,  0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk);
+DEFINE_CLOCK(wdt_clk,    0, CCM_CGCR2, 19, get_rate_ipg, NULL,  NULL);
+DEFINE_CLOCK(ssi1_clk,  0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk);
+DEFINE_CLOCK(ssi2_clk,  1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk);
+DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL);
+DEFINE_CLOCK(csi_clk,    0, CCM_CGCR1,  4, get_rate_csi, NULL,  &csi_per_clk);
+DEFINE_CLOCK(can1_clk,  0, CCM_CGCR1,  2, get_rate_ipg, NULL, NULL);
+DEFINE_CLOCK(can2_clk,  0, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
 
 #define _REGISTER_CLOCK(d, n, c)       \
        {                               \
@@ -217,7 +268,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
        _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk)
        _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk)
-       _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk)
+       _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk)
        _REGISTER_CLOCK("mx25-adc", NULL, tsc_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk)
@@ -225,6 +276,13 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk)
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
+       _REGISTER_CLOCK("imx-wdt.0", NULL, wdt_clk)
+       _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+       _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+       _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
+       _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
+       _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
+       _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
 };
 
 int __init mx25_clocks_init(void)
@@ -238,9 +296,13 @@ int __init mx25_clocks_init(void)
        __raw_writel((1 << 19), CRM_BASE + CCM_CGCR0);
        __raw_writel((0xf << 16) | (3 << 26), CRM_BASE + CCM_CGCR1);
        __raw_writel((1 << 5), CRM_BASE + CCM_CGCR2);
+#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
+       clk_enable(&uart1_clk);
+#endif
 
-       /* Clock source for lcdc is upll */
-       __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7), CRM_BASE + 0x64);
+       /* Clock source for lcdc and csi is upll */
+       __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7) | (1 << 0),
+                       CRM_BASE + 0x64);
 
        mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
 
diff --git a/arch/arm/mach-mx25/devices-imx25.h b/arch/arm/mach-mx25/devices-imx25.h
new file mode 100644 (file)
index 0000000..d86a7c3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/mx25.h>
+#include <mach/devices-common.h>
+
+#define imx25_add_flexcan0(pdata)      \
+       imx_add_flexcan(0, MX25_CAN1_BASE_ADDR, SZ_16K, MX25_INT_CAN1, pdata)
+#define imx25_add_flexcan1(pdata)      \
+       imx_add_flexcan(1, MX25_CAN2_BASE_ADDR, SZ_16K, MX25_INT_CAN2, pdata)
+
+#define imx25_add_imx_i2c0(pdata)      \
+       imx_add_imx_i2c(0, MX25_I2C1_BASE_ADDR, SZ_16K, MX25_INT_I2C1, pdata)
+#define imx25_add_imx_i2c1(pdata)      \
+       imx_add_imx_i2c(1, MX25_I2C2_BASE_ADDR, SZ_16K, MX25_INT_I2C2, pdata)
+#define imx25_add_imx_i2c2(pdata)      \
+       imx_add_imx_i2c(2, MX25_I2C3_BASE_ADDR, SZ_16K, MX25_INT_I2C3, pdata)
+
+#define imx25_add_imx_uart0(pdata)     \
+       imx_add_imx_uart_1irq(0, MX25_UART1_BASE_ADDR, SZ_16K, MX25_INT_UART1, pdata)
+#define imx25_add_imx_uart1(pdata)     \
+       imx_add_imx_uart_1irq(1, MX25_UART2_BASE_ADDR, SZ_16K, MX25_INT_UART2, pdata)
+#define imx25_add_imx_uart2(pdata)     \
+       imx_add_imx_uart_1irq(2, MX25_UART3_BASE_ADDR, SZ_16K, MX25_INT_UART3, pdata)
+#define imx25_add_imx_uart3(pdata)     \
+       imx_add_imx_uart_1irq(3, MX25_UART4_BASE_ADDR, SZ_16K, MX25_INT_UART4, pdata)
+#define imx25_add_imx_uart4(pdata)     \
+       imx_add_imx_uart_1irq(4, MX25_UART5_BASE_ADDR, SZ_16K, MX25_INT_UART5, pdata)
+
+#define imx25_add_mxc_nand(pdata)      \
+       imx_add_mxc_nand_v21(MX25_NFC_BASE_ADDR, MX25_INT_NANDFC, pdata)
+
+#define imx25_add_spi_imx0(pdata)      \
+       imx_add_spi_imx(0, MX25_CSPI1_BASE_ADDR, SZ_16K, MX25_INT_CSPI1, pdata)
+#define imx25_add_spi_imx1(pdata)      \
+       imx_add_spi_imx(1, MX25_CSPI2_BASE_ADDR, SZ_16K, MX25_INT_CSPI2, pdata)
+#define imx25_add_spi_imx2(pdata)      \
+       imx_add_spi_imx(2, MX25_CSPI3_BASE_ADDR, SZ_16K, MX25_INT_CSPI3, pdata)
index 3a405fa400eb064a6a8e612027709b7601cb4d34..3468eb15b2367fd1a4c197bf76d3b59af4b3372a 100644 (file)
 #include <mach/mx25.h>
 #include <mach/irqs.h>
 
-static struct resource uart0[] = {
-       {
-               .start = 0x43f90000,
-               .end = 0x43f93fff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 45,
-               .end = 45,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device0 = {
-       .name = "imx-uart",
-       .id = 0,
-       .resource = uart0,
-       .num_resources = ARRAY_SIZE(uart0),
-};
-
-static struct resource uart1[] = {
-       {
-               .start = 0x43f94000,
-               .end = 0x43f97fff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 32,
-               .end = 32,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device1 = {
-       .name = "imx-uart",
-       .id = 1,
-       .resource = uart1,
-       .num_resources = ARRAY_SIZE(uart1),
-};
-
-static struct resource uart2[] = {
-       {
-               .start = 0x5000c000,
-               .end = 0x5000ffff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 18,
-               .end = 18,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device2 = {
-       .name = "imx-uart",
-       .id = 2,
-       .resource = uart2,
-       .num_resources = ARRAY_SIZE(uart2),
-};
-
-static struct resource uart3[] = {
-       {
-               .start = 0x50008000,
-               .end = 0x5000bfff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 5,
-               .end = 5,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device3 = {
-       .name = "imx-uart",
-       .id = 3,
-       .resource = uart3,
-       .num_resources = ARRAY_SIZE(uart3),
-};
-
-static struct resource uart4[] = {
-       {
-               .start = 0x5002c000,
-               .end = 0x5002ffff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = 40,
-               .end = 40,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device4 = {
-       .name = "imx-uart",
-       .id = 4,
-       .resource = uart4,
-       .num_resources = ARRAY_SIZE(uart4),
-};
-
-#define MX25_OTG_BASE_ADDR 0x53FF4000
-
 static u64 otg_dmamask = DMA_BIT_MASK(32);
 
 static struct resource mxc_otg_resources[] = {
@@ -181,63 +84,6 @@ struct platform_device mxc_usbh2 = {
        .num_resources = ARRAY_SIZE(mxc_usbh2_resources),
 };
 
-static struct resource mxc_spi_resources0[] = {
-       {
-              .start = 0x43fa4000,
-              .end = 0x43fa7fff,
-              .flags = IORESOURCE_MEM,
-       }, {
-              .start = 14,
-              .end = 14,
-              .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_spi_device0 = {
-       .name = "spi_imx",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_spi_resources0),
-       .resource = mxc_spi_resources0,
-};
-
-static struct resource mxc_spi_resources1[] = {
-       {
-              .start = 0x50010000,
-              .end = 0x50013fff,
-              .flags = IORESOURCE_MEM,
-       }, {
-              .start = 13,
-              .end = 13,
-              .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_spi_device1 = {
-       .name = "spi_imx",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_spi_resources1),
-       .resource = mxc_spi_resources1,
-};
-
-static struct resource mxc_spi_resources2[] = {
-       {
-              .start = 0x50004000,
-              .end = 0x50007fff,
-              .flags = IORESOURCE_MEM,
-       }, {
-              .start = 0,
-              .end = 0,
-              .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_spi_device2 = {
-       .name = "spi_imx",
-       .id = 2,
-       .num_resources = ARRAY_SIZE(mxc_spi_resources2),
-       .resource = mxc_spi_resources2,
-};
-
 static struct resource mxc_pwm_resources0[] = {
        {
                .start  = 0x53fe0000,
@@ -333,63 +179,6 @@ struct platform_device mxc_pwm_device3 = {
        .resource = mxc_pwm_resources3,
 };
 
-static struct resource mxc_i2c_1_resources[] = {
-       {
-               .start  = 0x43f80000,
-               .end    = 0x43f83fff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = 3,
-               .end    = 3,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-struct platform_device mxc_i2c_device0 = {
-       .name = "imx-i2c",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_i2c_1_resources),
-       .resource = mxc_i2c_1_resources,
-};
-
-static struct resource mxc_i2c_2_resources[] = {
-       {
-               .start  = 0x43f98000,
-               .end    = 0x43f9bfff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = 4,
-               .end    = 4,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-struct platform_device mxc_i2c_device1 = {
-       .name = "imx-i2c",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_i2c_2_resources),
-       .resource = mxc_i2c_2_resources,
-};
-
-static struct resource mxc_i2c_3_resources[] = {
-       {
-               .start  = 0x43f84000,
-               .end    = 0x43f87fff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = 10,
-               .end    = 10,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-struct platform_device mxc_i2c_device2 = {
-       .name = "imx-i2c",
-       .id = 2,
-       .num_resources = ARRAY_SIZE(mxc_i2c_3_resources),
-       .resource = mxc_i2c_3_resources,
-};
-
 static struct mxc_gpio_port imx_gpio_ports[] = {
        {
                .chip.label = "gpio-0",
@@ -414,7 +203,7 @@ static struct mxc_gpio_port imx_gpio_ports[] = {
        }
 };
 
-int __init mxc_register_gpios(void)
+int __init imx25_register_gpios(void)
 {
        return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 }
@@ -439,26 +228,6 @@ struct platform_device mx25_fec_device = {
        .resource       = mx25_fec_resources,
 };
 
-static struct resource mxc_nand_resources[] = {
-       {
-               .start  = MX25_NFC_BASE_ADDR,
-               .end    = MX25_NFC_BASE_ADDR + 0x1fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = MX25_INT_NANDFC,
-               .end    = MX25_INT_NANDFC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_nand_device = {
-       .name           = "mxc_nand",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(mxc_nand_resources),
-       .resource       = mxc_nand_resources,
-};
-
 static struct resource mx25_rtc_resources[] = {
        {
                .start  = MX25_DRYICE_BASE_ADDR,
@@ -515,3 +284,83 @@ struct platform_device mxc_wdt = {
        .num_resources = ARRAY_SIZE(mxc_wdt_resources),
        .resource = mxc_wdt_resources,
 };
+
+static struct resource mx25_kpp_resources[] = {
+       {
+               .start  = MX25_KPP_BASE_ADDR,
+               .end    = MX25_KPP_BASE_ADDR + 0xf,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = MX25_INT_KPP,
+               .end    = MX25_INT_KPP,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device mx25_kpp_device = {
+       .name   = "imx-keypad",
+       .id     = -1,
+       .num_resources  = ARRAY_SIZE(mx25_kpp_resources),
+       .resource       = mx25_kpp_resources,
+};
+
+static struct resource imx_ssi_resources0[] = {
+       {
+               .start  = MX25_SSI1_BASE_ADDR,
+               .end    = MX25_SSI1_BASE_ADDR + 0x3fff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MX25_INT_SSI1,
+               .end    = MX25_INT_SSI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource imx_ssi_resources1[] = {
+       {
+               .start  = MX25_SSI2_BASE_ADDR,
+               .end    = MX25_SSI2_BASE_ADDR + 0x3fff,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = MX25_INT_SSI2,
+               .end    = MX25_INT_SSI2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_ssi_device0 = {
+       .name = "imx-ssi",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(imx_ssi_resources0),
+       .resource = imx_ssi_resources0,
+};
+
+struct platform_device imx_ssi_device1 = {
+       .name = "imx-ssi",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(imx_ssi_resources1),
+       .resource = imx_ssi_resources1,
+};
+
+static struct resource mx25_csi_resources[] = {
+       {
+               .start  = MX25_CSI_BASE_ADDR,
+               .end    = MX25_CSI_BASE_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = MX25_INT_CSI,
+               .flags  = IORESOURCE_IRQ
+       },
+};
+
+struct platform_device mx25_csi_device = {
+       .name   = "mx2-camera",
+       .id     = 0,
+       .num_resources  = ARRAY_SIZE(mx25_csi_resources),
+       .resource       = mx25_csi_resources,
+       .dev            = {
+               .coherent_dma_mask = 0xffffffff,
+       },
+};
index cee12c0a0be68e5988fcc8f914c94705dfe92beb..4aceb68e35a77003e11505dfb3eca338006263fb 100644 (file)
@@ -1,24 +1,16 @@
-extern struct platform_device mxc_uart_device0;
-extern struct platform_device mxc_uart_device1;
-extern struct platform_device mxc_uart_device2;
-extern struct platform_device mxc_uart_device3;
-extern struct platform_device mxc_uart_device4;
 extern struct platform_device mxc_otg;
 extern struct platform_device otg_udc_device;
 extern struct platform_device mxc_usbh2;
-extern struct platform_device mxc_spi_device0;
-extern struct platform_device mxc_spi_device1;
-extern struct platform_device mxc_spi_device2;
 extern struct platform_device mxc_pwm_device0;
 extern struct platform_device mxc_pwm_device1;
 extern struct platform_device mxc_pwm_device2;
 extern struct platform_device mxc_pwm_device3;
 extern struct platform_device mxc_keypad_device;
-extern struct platform_device mxc_i2c_device0;
-extern struct platform_device mxc_i2c_device1;
-extern struct platform_device mxc_i2c_device2;
 extern struct platform_device mx25_fec_device;
-extern struct platform_device mxc_nand_device;
 extern struct platform_device mx25_rtc_device;
 extern struct platform_device mx25_fb_device;
 extern struct platform_device mxc_wdt;
+extern struct platform_device mx25_kpp_device;
+extern struct platform_device imx_ssi_device0;
+extern struct platform_device imx_ssi_device1;
+extern struct platform_device mx25_csi_device;
diff --git a/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c
new file mode 100644 (file)
index 0000000..91931dc
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
+ *
+ * Based on pcm970-baseboard.c which is :
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <video/platform_lcd.h>
+
+#include <mach/hardware.h>
+#include <mach/iomux-mx25.h>
+#include <mach/common.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/mx25.h>
+#include <mach/imx-uart.h>
+#include <mach/imxfb.h>
+#include <mach/ssi.h>
+#include <mach/audmux.h>
+
+#include "devices-imx25.h"
+#include "devices.h"
+
+static struct pad_desc eukrea_mbimxsd_pads[] = {
+       /* LCD */
+       MX25_PAD_LD0__LD0,
+       MX25_PAD_LD1__LD1,
+       MX25_PAD_LD2__LD2,
+       MX25_PAD_LD3__LD3,
+       MX25_PAD_LD4__LD4,
+       MX25_PAD_LD5__LD5,
+       MX25_PAD_LD6__LD6,
+       MX25_PAD_LD7__LD7,
+       MX25_PAD_LD8__LD8,
+       MX25_PAD_LD9__LD9,
+       MX25_PAD_LD10__LD10,
+       MX25_PAD_LD11__LD11,
+       MX25_PAD_LD12__LD12,
+       MX25_PAD_LD13__LD13,
+       MX25_PAD_LD14__LD14,
+       MX25_PAD_LD15__LD15,
+       MX25_PAD_GPIO_E__LD16,
+       MX25_PAD_GPIO_F__LD17,
+       MX25_PAD_HSYNC__HSYNC,
+       MX25_PAD_VSYNC__VSYNC,
+       MX25_PAD_LSCLK__LSCLK,
+       MX25_PAD_OE_ACD__OE_ACD,
+       MX25_PAD_CONTRAST__CONTRAST,
+       /* LCD_PWR */
+       MX25_PAD_PWM__GPIO_1_26,
+       /* LED */
+       MX25_PAD_POWER_FAIL__GPIO_3_19,
+       /* SWITCH */
+       MX25_PAD_VSTBY_ACK__GPIO_3_18,
+       /* UART2 */
+       MX25_PAD_UART2_RTS__UART2_RTS,
+       MX25_PAD_UART2_CTS__UART2_CTS,
+       MX25_PAD_UART2_TXD__UART2_TXD,
+       MX25_PAD_UART2_RXD__UART2_RXD,
+       /* SD1 */
+       MX25_PAD_SD1_CMD__SD1_CMD,
+       MX25_PAD_SD1_CLK__SD1_CLK,
+       MX25_PAD_SD1_DATA0__SD1_DATA0,
+       MX25_PAD_SD1_DATA1__SD1_DATA1,
+       MX25_PAD_SD1_DATA2__SD1_DATA2,
+       MX25_PAD_SD1_DATA3__SD1_DATA3,
+       /* SD1 CD */
+       MX25_PAD_DE_B__GPIO_2_20,
+       /* I2S */
+       MX25_PAD_KPP_COL3__AUD5_TXFS,
+       MX25_PAD_KPP_COL2__AUD5_TXC,
+       MX25_PAD_KPP_COL1__AUD5_RXD,
+       MX25_PAD_KPP_COL0__AUD5_TXD,
+};
+
+#define GPIO_LED1      83
+#define GPIO_SWITCH1   82
+#define GPIO_SD1CD     52
+#define GPIO_LCDPWR    26
+
+static struct imx_fb_videomode eukrea_mximxsd_modes[] = {
+       {
+               .mode   = {
+                       .name           = "CMO-QVGA",
+                       .refresh        = 60,
+                       .xres           = 320,
+                       .yres           = 240,
+                       .pixclock       = KHZ2PICOS(6500),
+                       .left_margin    = 30,
+                       .right_margin   = 38,
+                       .upper_margin   = 20,
+                       .lower_margin   = 3,
+                       .hsync_len      = 15,
+                       .vsync_len      = 4,
+               },
+               .bpp    = 16,
+               .pcr    = 0xCAD08B80,
+       },
+};
+
+static struct imx_fb_platform_data eukrea_mximxsd_fb_pdata = {
+       .mode           = eukrea_mximxsd_modes,
+       .num_modes      = ARRAY_SIZE(eukrea_mximxsd_modes),
+       .pwmr           = 0x00A903FF,
+       .lscr1          = 0x00120300,
+       .dmacr          = 0x00040060,
+};
+
+static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd,
+                                  unsigned int power)
+{
+       if (power)
+               gpio_direction_output(GPIO_LCDPWR, 1);
+       else
+               gpio_direction_output(GPIO_LCDPWR, 0);
+}
+
+static struct plat_lcd_data eukrea_mbimxsd_lcd_power_data = {
+       .set_power              = eukrea_mbimxsd_lcd_power_set,
+};
+
+static struct platform_device eukrea_mbimxsd_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.platform_data      = &eukrea_mbimxsd_lcd_power_data,
+};
+
+static struct gpio_led eukrea_mbimxsd_leds[] = {
+       {
+               .name                   = "led1",
+               .default_trigger        = "heartbeat",
+               .active_low             = 1,
+               .gpio                   = GPIO_LED1,
+       },
+};
+
+static struct gpio_led_platform_data eukrea_mbimxsd_led_info = {
+       .leds           = eukrea_mbimxsd_leds,
+       .num_leds       = ARRAY_SIZE(eukrea_mbimxsd_leds),
+};
+
+static struct platform_device eukrea_mbimxsd_leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &eukrea_mbimxsd_led_info,
+       },
+};
+
+static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
+       {
+               .gpio           = GPIO_SWITCH1,
+               .code           = BTN_0,
+               .desc           = "BP1",
+               .active_low     = 1,
+               .wakeup         = 1,
+       },
+};
+
+static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+       .buttons        = eukrea_mbimxsd_gpio_buttons,
+       .nbuttons       = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
+};
+
+static struct platform_device eukrea_mbimxsd_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &eukrea_mbimxsd_button_data,
+       }
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &eukrea_mbimxsd_leds_gpio,
+       &eukrea_mbimxsd_button_device,
+       &eukrea_mbimxsd_lcd_powerdev,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       },
+};
+
+struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = {
+       .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
+};
+
+/*
+ * system init for baseboard usage. Will be called by cpuimx25 init.
+ *
+ * Add platform devices present on this baseboard and init
+ * them from CPU side as far as required to use them later on
+ */
+void __init eukrea_mbimxsd_baseboard_init(void)
+{
+       if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
+                       ARRAY_SIZE(eukrea_mbimxsd_pads)))
+               printk(KERN_ERR "error setting mbimxsd pads !\n");
+
+#if defined(CONFIG_SND_SOC_EUKREA_TLV320)
+       /* SSI unit master I2S codec connected to SSI_AUD5*/
+       mxc_audmux_v2_configure_port(0,
+                       MXC_AUDMUX_V2_PTCR_SYN |
+                       MXC_AUDMUX_V2_PTCR_TFSDIR |
+                       MXC_AUDMUX_V2_PTCR_TFSEL(4) |
+                       MXC_AUDMUX_V2_PTCR_TCLKDIR |
+                       MXC_AUDMUX_V2_PTCR_TCSEL(4),
+                       MXC_AUDMUX_V2_PDCR_RXDSEL(4)
+       );
+       mxc_audmux_v2_configure_port(4,
+                       MXC_AUDMUX_V2_PTCR_SYN,
+                       MXC_AUDMUX_V2_PDCR_RXDSEL(0)
+       );
+#endif
+
+       imx25_add_imx_uart1(&uart_pdata);
+       mxc_register_device(&mx25_fb_device, &eukrea_mximxsd_fb_pdata);
+       mxc_register_device(&imx_ssi_device0, &eukrea_mbimxsd_ssi_pdata);
+
+       gpio_request(GPIO_LED1, "LED1");
+       gpio_direction_output(GPIO_LED1, 1);
+       gpio_free(GPIO_LED1);
+
+       gpio_request(GPIO_SWITCH1, "SWITCH1");
+       gpio_direction_input(GPIO_SWITCH1);
+       gpio_free(GPIO_SWITCH1);
+
+       gpio_request(GPIO_LCDPWR, "LCDPWR");
+       gpio_direction_output(GPIO_LCDPWR, 1);
+       gpio_free(GPIO_SWITCH1);
+
+       i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
+                               ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
+
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
diff --git a/arch/arm/mach-mx25/mach-cpuimx25.c b/arch/arm/mach-mx25/mach-cpuimx25.c
new file mode 100644 (file)
index 0000000..56b2e26
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2009 Sascha Hauer, <kernel@pengutronix.de>
+ * Copyright 2010 Eric Bénard - Eukréa Electromatique, <eric@eukrea.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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/fec.h>
+#include <linux/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/fsl_devices.h>
+
+#include <mach/eukrea-baseboards.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/memory.h>
+#include <asm/mach/map.h>
+#include <mach/common.h>
+#include <mach/mx25.h>
+#include <mach/mxc_nand.h>
+#include <mach/imxfb.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
+#include <mach/iomux-mx25.h>
+
+#include "devices-imx25.h"
+#include "devices.h"
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct pad_desc eukrea_cpuimx25_pads[] = {
+       /* FEC - RMII */
+       MX25_PAD_FEC_MDC__FEC_MDC,
+       MX25_PAD_FEC_MDIO__FEC_MDIO,
+       MX25_PAD_FEC_TDATA0__FEC_TDATA0,
+       MX25_PAD_FEC_TDATA1__FEC_TDATA1,
+       MX25_PAD_FEC_TX_EN__FEC_TX_EN,
+       MX25_PAD_FEC_RDATA0__FEC_RDATA0,
+       MX25_PAD_FEC_RDATA1__FEC_RDATA1,
+       MX25_PAD_FEC_RX_DV__FEC_RX_DV,
+       MX25_PAD_FEC_TX_CLK__FEC_TX_CLK,
+       /* I2C1 */
+       MX25_PAD_I2C1_CLK__I2C1_CLK,
+       MX25_PAD_I2C1_DAT__I2C1_DAT,
+};
+
+static struct fec_platform_data mx25_fec_pdata = {
+       .phy    = PHY_INTERFACE_MODE_RMII,
+};
+
+static const struct mxc_nand_platform_data
+eukrea_cpuimx25_nand_board_info __initconst = {
+       .width          = 1,
+       .hw_ecc         = 1,
+       .flash_bbt      = 1,
+};
+
+static const struct imxi2c_platform_data
+eukrea_cpuimx25_i2c0_data __initconst = {
+       .bitrate = 100000,
+};
+
+static struct i2c_board_info eukrea_cpuimx25_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pcf8563", 0x51),
+       },
+};
+
+static struct mxc_usbh_platform_data otg_pdata = {
+       .portsc = MXC_EHCI_MODE_UTMI,
+       .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
+};
+
+static struct mxc_usbh_platform_data usbh2_pdata = {
+       .portsc = MXC_EHCI_MODE_SERIAL,
+       .flags  = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
+                 MXC_EHCI_IPPUE_DOWN,
+};
+
+static struct fsl_usb2_platform_data otg_device_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_UTMI,
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx25_otg_mode(char *options)
+{
+       if (!strcmp(options, "host"))
+               otg_mode_host = 1;
+       else if (!strcmp(options, "device"))
+               otg_mode_host = 0;
+       else
+               pr_info("otg_mode neither \"host\" nor \"device\". "
+                       "Defaulting to device\n");
+       return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx25_otg_mode);
+
+static void __init eukrea_cpuimx25_init(void)
+{
+       if (mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx25_pads,
+                       ARRAY_SIZE(eukrea_cpuimx25_pads)))
+               printk(KERN_ERR "error setting cpuimx25 pads !\n");
+
+       imx25_add_imx_uart0(&uart_pdata);
+       imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info);
+       mxc_register_device(&mx25_rtc_device, NULL);
+       mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+
+       i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices,
+                               ARRAY_SIZE(eukrea_cpuimx25_i2c_devices));
+       imx25_add_imx_i2c0(&eukrea_cpuimx25_i2c0_data);
+
+#if defined(CONFIG_USB_ULPI)
+       if (otg_mode_host) {
+               otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                               USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+               mxc_register_device(&mxc_otg, &otg_pdata);
+       }
+       mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+#endif
+       if (!otg_mode_host)
+               mxc_register_device(&otg_udc_device, &otg_device_pdata);
+
+#ifdef CONFIG_MACH_EUKREA_MBIMXSD_BASEBOARD
+       eukrea_mbimxsd_baseboard_init();
+#endif
+}
+
+static void __init eukrea_cpuimx25_timer_init(void)
+{
+       mx25_clocks_init();
+}
+
+static struct sys_timer eukrea_cpuimx25_timer = {
+       .init   = eukrea_cpuimx25_timer_init,
+};
+
+MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25")
+       /* Maintainer: Eukrea Electromatique */
+       .phys_io        = MX25_AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((MX25_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = MX25_PHYS_OFFSET + 0x100,
+       .map_io         = mx25_map_io,
+       .init_irq       = mx25_init_irq,
+       .init_machine   = eukrea_cpuimx25_init,
+       .timer          = &eukrea_cpuimx25_timer,
+MACHINE_END
similarity index 76%
rename from arch/arm/mach-mx25/mach-mx25pdk.c
rename to arch/arm/mach-mx25/mach-mx25_3ds.c
index 83d74109e7d837fb8e53f4c803652e4bae4cae4d..62bc21f11a714aa46df5e439d4965f340d59460a 100644 (file)
  * Boston, MA  02110-1301, USA.
  */
 
+/*
+ * This machine is known as:
+ *  - i.MX25 3-Stack Development System
+ *  - i.MX25 Platform Development Kit (i.MX25 PDK)
+ */
+
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -24,6 +30,7 @@
 #include <linux/gpio.h>
 #include <linux/fec.h>
 #include <linux/platform_device.h>
+#include <linux/input/matrix_keypad.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/mx25.h>
-#include <mach/mxc_nand.h>
 #include <mach/imxfb.h>
-#include "devices.h"
 #include <mach/iomux-mx25.h>
 
-static struct imxuart_platform_data uart_pdata = {
+#include "devices-imx25.h"
+#include "devices.h"
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -80,6 +87,16 @@ static struct pad_desc mx25pdk_pads[] = {
        MX25_PAD_LSCLK__LSCLK,
        MX25_PAD_OE_ACD__OE_ACD,
        MX25_PAD_CONTRAST__CONTRAST,
+
+       /* Keypad */
+       MX25_PAD_KPP_ROW0__KPP_ROW0,
+       MX25_PAD_KPP_ROW1__KPP_ROW1,
+       MX25_PAD_KPP_ROW2__KPP_ROW2,
+       MX25_PAD_KPP_ROW3__KPP_ROW3,
+       MX25_PAD_KPP_COL0__KPP_COL0,
+       MX25_PAD_KPP_COL1__KPP_COL1,
+       MX25_PAD_KPP_COL2__KPP_COL2,
+       MX25_PAD_KPP_COL3__KPP_COL3,
 };
 
 static struct fec_platform_data mx25_fec_pdata = {
@@ -103,7 +120,8 @@ static void __init mx25pdk_fec_reset(void)
        gpio_set_value(FEC_RESET_B_GPIO, 1);
 }
 
-static struct mxc_nand_platform_data mx25pdk_nand_board_info = {
+static const struct mxc_nand_platform_data
+mx25pdk_nand_board_info __initconst = {
        .width          = 1,
        .hw_ecc         = 1,
        .flash_bbt      = 1,
@@ -137,19 +155,45 @@ static struct imx_fb_platform_data mx25pdk_fb_pdata = {
        .dmacr          = 0x00020010,
 };
 
+static const uint32_t mx25pdk_keymap[] = {
+       KEY(0, 0, KEY_UP),
+       KEY(0, 1, KEY_DOWN),
+       KEY(0, 2, KEY_VOLUMEDOWN),
+       KEY(0, 3, KEY_HOME),
+       KEY(1, 0, KEY_RIGHT),
+       KEY(1, 1, KEY_LEFT),
+       KEY(1, 2, KEY_ENTER),
+       KEY(1, 3, KEY_VOLUMEUP),
+       KEY(2, 0, KEY_F6),
+       KEY(2, 1, KEY_F8),
+       KEY(2, 2, KEY_F9),
+       KEY(2, 3, KEY_F10),
+       KEY(3, 0, KEY_F1),
+       KEY(3, 1, KEY_F2),
+       KEY(3, 2, KEY_F3),
+       KEY(3, 3, KEY_POWER),
+};
+
+static struct matrix_keymap_data mx25pdk_keymap_data = {
+       .keymap         = mx25pdk_keymap,
+       .keymap_size    = ARRAY_SIZE(mx25pdk_keymap),
+};
+
 static void __init mx25pdk_init(void)
 {
        mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
                        ARRAY_SIZE(mx25pdk_pads));
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx25_add_imx_uart0(&uart_pdata);
        mxc_register_device(&mxc_usbh2, NULL);
-       mxc_register_device(&mxc_nand_device, &mx25pdk_nand_board_info);
+       imx25_add_mxc_nand(&mx25pdk_nand_board_info);
        mxc_register_device(&mx25_rtc_device, NULL);
        mxc_register_device(&mx25_fb_device, &mx25pdk_fb_pdata);
+       mxc_register_device(&mxc_wdt, NULL);
 
        mx25pdk_fec_reset();
        mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+       mxc_register_device(&mx25_kpp_device, &mx25pdk_keymap_data);
 }
 
 static void __init mx25pdk_timer_init(void)
index a7e587ff3e9ebc5b0821f4a506548b7bd7e1b817..bb677111fb0f11cca20f5ff143cf397412b92587 100644 (file)
  * 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/mm.h>
@@ -69,8 +65,11 @@ void __init mx25_map_io(void)
        iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
 
+int imx25_register_gpios(void);
+
 void __init mx25_init_irq(void)
 {
        mxc_init_irq((void __iomem *)MX25_AVIC_BASE_ADDR_VIRT);
+       imx25_register_gpios();
 }
 
index 344753fdf25ef47ac6856ff5058f9cc8a193120a..85beece802aab702a71331f63fd6ff7065adb7bb 100644 (file)
@@ -15,6 +15,8 @@ comment "MX3 platforms:"
 config MACH_MX31ADS
        bool "Support MX31ADS platforms"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
        default y
        help
          Include support for MX31ADS platform. This includes specific
@@ -34,6 +36,9 @@ config MACH_MX31ADS_WM1133_EV1
 config MACH_PCM037
        bool "Support Phytec pcm037 (i.MX31) platforms"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        select MXC_ULPI if USB_ULPI
        help
          Include support for Phytec pcm037 platform. This includes
@@ -42,6 +47,7 @@ config MACH_PCM037
 config MACH_PCM037_EET
        bool "Support pcm037 EET board extensions"
        depends on MACH_PCM037
+       select IMX_HAVE_PLATFORM_SPI_IMX
        help
          Add support for PCM037 EET baseboard extensions. If you are using the
          OLED display with EET, use "video=mx3fb:CMEL-OLED" kernel
@@ -51,6 +57,9 @@ config MACH_MX31LITE
        bool "Support MX31 LITEKIT (LogicPD)"
        select ARCH_MX31
        select MXC_ULPI if USB_ULPI
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_SPI_IMX
        help
          Include support for MX31 LITEKIT platform. This includes specific
          configurations for the board and its peripherals.
@@ -58,6 +67,10 @@ config MACH_MX31LITE
 config MACH_MX31_3DS
        bool "Support MX31PDK (3DS)"
        select ARCH_MX31
+       select MXC_DEBUG_BOARD
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_SPI_IMX
        help
          Include support for MX31PDK (3DS) platform. This includes specific
          configurations for the board and its peripherals.
@@ -74,6 +87,9 @@ config MACH_MX31_3DS_MXC_NAND_USE_BBT
 config MACH_MX31MOBOARD
        bool "Support mx31moboard platforms (EPFL Mobots group)"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_SPI_IMX
        select MXC_ULPI if USB_ULPI
        help
          Include support for mx31moboard platform. This includes specific
@@ -82,6 +98,8 @@ config MACH_MX31MOBOARD
 config MACH_MX31LILLY
        bool "Support MX31 LILLY-1131 platforms (INCO startec)"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_SPI_IMX
        select MXC_ULPI if USB_ULPI
        help
          Include support for mx31 based LILLY1131 modules. This includes
@@ -90,6 +108,7 @@ config MACH_MX31LILLY
 config MACH_QONG
        bool "Support Dave/DENX QongEVB-LITE platform"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_UART
        help
          Include support for Dave/DENX QongEVB-LITE platform. This includes
          specific configurations for the board and its peripherals.
@@ -97,6 +116,10 @@ config MACH_QONG
 config MACH_PCM043
        bool "Support Phytec pcm043 (i.MX35) platforms"
        select ARCH_MX35
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_FLEXCAN
        select MXC_ULPI if USB_ULPI
        help
          Include support for Phytec pcm043 platform. This includes
@@ -105,6 +128,9 @@ config MACH_PCM043
 config MACH_ARMADILLO5X0
        bool "Support Atmark Armadillo-500 Development Base Board"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        select MXC_ULPI if USB_ULPI
        help
          Include support for Atmark Armadillo-500 platform. This includes
@@ -113,6 +139,7 @@ config MACH_ARMADILLO5X0
 config MACH_MX35_3DS
        bool "Support MX35PDK platform"
        select ARCH_MX35
+       select IMX_HAVE_PLATFORM_IMX_UART
        default n
        help
          Include support for MX35PDK platform. This includes specific
@@ -121,8 +148,34 @@ config MACH_MX35_3DS
 config MACH_KZM_ARM11_01
        bool "Support KZM-ARM11-01(Kyoto Microcomputer)"
        select ARCH_MX31
+       select IMX_HAVE_PLATFORM_IMX_UART
        help
          Include support for KZM-ARM11-01. This includes specific
          configurations for the board and its peripherals.
 
+config MACH_EUKREA_CPUIMX35
+       bool "Support Eukrea CPUIMX35 Platform"
+       select ARCH_MX35
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select MXC_ULPI if USB_ULPI
+       help
+         Include support for Eukrea CPUIMX35 platform. This includes
+         specific configurations for the board and its peripherals.
+
+choice
+       prompt "Baseboard"
+       depends on MACH_EUKREA_CPUIMX35
+       default MACH_EUKREA_MBIMXSD35_BASEBOARD
+
+config MACH_EUKREA_MBIMXSD35_BASEBOARD
+       prompt "Eukrea MBIMXSD development board"
+       bool
+       help
+         This adds board specific devices that can be found on Eukrea's
+         MBIMXSD evaluation board.
+
+endchoice
+
 endif
index 5d650fda5d5d3f0653c0cedc287068d98eb0a476..2bd7beceb99182879a7100d14e6d54dd5cdac6a2 100644 (file)
@@ -22,5 +22,7 @@ obj-$(CONFIG_MACH_MX31MOBOARD)        += mach-mx31moboard.o mx31moboard-devboard.o \
 obj-$(CONFIG_MACH_QONG)                += mach-qong.o
 obj-$(CONFIG_MACH_PCM043)      += mach-pcm043.o
 obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o
-obj-$(CONFIG_MACH_MX35_3DS)    += mach-mx35pdk.o
+obj-$(CONFIG_MACH_MX35_3DS)    += mach-mx35_3ds.o
 obj-$(CONFIG_MACH_KZM_ARM11_01)        += mach-kzm_arm11_01.o
+obj-$(CONFIG_MACH_EUKREA_CPUIMX35)     += mach-cpuimx35.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD)  += eukrea_mbimxsd-baseboard.o
index 9f3e943e22326cf0b0f8024194414de457a66356..d3af0fdf8475f7ef0d67b3afbb080df739c36431 100644 (file)
@@ -359,7 +359,7 @@ DEFINE_CLOCK(i2c1_clk,   0, CCM_CGR1, 10, get_rate_ipg_per, NULL);
 DEFINE_CLOCK(i2c2_clk,   1, CCM_CGR1, 12, get_rate_ipg_per, NULL);
 DEFINE_CLOCK(i2c3_clk,   2, CCM_CGR1, 14, get_rate_ipg_per, NULL);
 DEFINE_CLOCK(iomuxc_clk, 0, CCM_CGR1, 16, NULL, NULL);
-DEFINE_CLOCK(ipu_clk,    0, CCM_CGR1, 18, NULL, NULL);
+DEFINE_CLOCK(ipu_clk,    0, CCM_CGR1, 18, get_rate_ahb, NULL);
 DEFINE_CLOCK(kpp_clk,    0, CCM_CGR1, 20, get_rate_ipg, NULL);
 DEFINE_CLOCK(mlb_clk,    0, CCM_CGR1, 22, get_rate_ahb, NULL);
 DEFINE_CLOCK(mshc_clk,   0, CCM_CGR1, 24, get_rate_mshc, NULL);
@@ -428,8 +428,8 @@ static struct clk nfc_clk = {
 static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "asrc", asrc_clk)
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
-       _REGISTER_CLOCK(NULL, "can", can1_clk)
-       _REGISTER_CLOCK(NULL, "can", can2_clk)
+       _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
+       _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
        _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
        _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
        _REGISTER_CLOCK(NULL, "ect", ect_clk)
diff --git a/arch/arm/mach-mx3/devices-imx31.h b/arch/arm/mach-mx3/devices-imx31.h
new file mode 100644 (file)
index 0000000..3b1a44a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/mx31.h>
+#include <mach/devices-common.h>
+
+#define imx31_add_imx_i2c0(pdata)      \
+       imx_add_imx_i2c(0, MX31_I2C1_BASE_ADDR, SZ_4K, MX31_INT_I2C1, pdata)
+#define imx31_add_imx_i2c1(pdata)      \
+       imx_add_imx_i2c(1, MX31_I2C2_BASE_ADDR, SZ_4K, MX31_INT_I2C2, pdata)
+#define imx31_add_imx_i2c2(pdata)      \
+       imx_add_imx_i2c(2, MX31_I2C3_BASE_ADDR, SZ_4K, MX31_INT_I2C3, pdata)
+
+#define imx31_add_imx_uart0(pdata)     \
+       imx_add_imx_uart_1irq(0, MX31_UART1_BASE_ADDR, SZ_16K, MX31_INT_UART1, pdata)
+#define imx31_add_imx_uart1(pdata)     \
+       imx_add_imx_uart_1irq(1, MX31_UART2_BASE_ADDR, SZ_16K, MX31_INT_UART2, pdata)
+#define imx31_add_imx_uart2(pdata)     \
+       imx_add_imx_uart_1irq(2, MX31_UART3_BASE_ADDR, SZ_16K, MX31_INT_UART3, pdata)
+#define imx31_add_imx_uart3(pdata)     \
+       imx_add_imx_uart_1irq(3, MX31_UART4_BASE_ADDR, SZ_16K, MX31_INT_UART4, pdata)
+#define imx31_add_imx_uart4(pdata)     \
+       imx_add_imx_uart_1irq(4, MX31_UART5_BASE_ADDR, SZ_16K, MX31_INT_UART5, pdata)
+
+#define imx31_add_mxc_nand(pdata)      \
+       imx_add_mxc_nand_v1(MX31_NFC_BASE_ADDR, MX31_INT_NANDFC, pdata)
+
+#define imx31_add_spi_imx0(pdata)      \
+       imx_add_spi_imx(0, MX31_CSPI1_BASE_ADDR, SZ_4K, MX31_INT_CSPI1, pdata)
+#define imx31_add_spi_imx1(pdata)      \
+       imx_add_spi_imx(1, MX31_CSPI2_BASE_ADDR, SZ_4K, MX31_INT_CSPI2, pdata)
+#define imx31_add_spi_imx2(pdata)      \
+       imx_add_spi_imx(2, MX31_CSPI3_BASE_ADDR, SZ_4K, MX31_INT_CSPI3, pdata)
diff --git a/arch/arm/mach-mx3/devices-imx35.h b/arch/arm/mach-mx3/devices-imx35.h
new file mode 100644 (file)
index 0000000..f6a431a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/mx35.h>
+#include <mach/devices-common.h>
+
+#define imx35_add_flexcan0(pdata)      \
+       imx_add_flexcan(0, MX35_CAN1_BASE_ADDR, SZ_16K, MX35_INT_CAN1, pdata)
+#define imx35_add_flexcan1(pdata)      \
+       imx_add_flexcan(1, MX35_CAN2_BASE_ADDR, SZ_16K, MX35_INT_CAN2, pdata)
+
+#define imx35_add_imx_i2c0(pdata)      \
+       imx_add_imx_i2c(0, MX35_I2C1_BASE_ADDR, SZ_4K, MX35_INT_I2C1, pdata)
+#define imx35_add_imx_i2c1(pdata)      \
+       imx_add_imx_i2c(1, MX35_I2C2_BASE_ADDR, SZ_4K, MX35_INT_I2C2, pdata)
+#define imx35_add_imx_i2c2(pdata)      \
+       imx_add_imx_i2c(2, MX35_I2C3_BASE_ADDR, SZ_4K, MX35_INT_I2C3, pdata)
+
+#define imx35_add_imx_uart0(pdata)     \
+       imx_add_imx_uart_1irq(0, MX35_UART1_BASE_ADDR, SZ_16K, MX35_INT_UART1, pdata)
+#define imx35_add_imx_uart1(pdata)     \
+       imx_add_imx_uart_1irq(1, MX35_UART2_BASE_ADDR, SZ_16K, MX35_INT_UART2, pdata)
+#define imx35_add_imx_uart2(pdata)     \
+       imx_add_imx_uart_1irq(2, MX35_UART3_BASE_ADDR, SZ_16K, MX35_INT_UART3, pdata)
+
+#define imx35_add_mxc_nand(pdata)      \
+       imx_add_mxc_nand_v21(MX35_NFC_BASE_ADDR, MX35_INT_NANDFC, pdata)
+
+#define imx35_add_spi_imx0(pdata)      \
+       imx_add_spi_imx(0, MX35_CSPI1_BASE_ADDR, SZ_4K, MX35_INT_CSPI1, pdata)
+#define imx35_add_spi_imx1(pdata)      \
+       imx_add_spi_imx(1, MX35_CSPI2_BASE_ADDR, SZ_4K, MX35_INT_CSPI2, pdata)
index db7acd6e910160cc230736ff3eb441eff255f2d0..a4fd1a26fc91982d200d76c7a152eb5c62610a7b 100644 (file)
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/mx3_camera.h>
 
 #include "devices.h"
 
-static struct resource uart0[] = {
-       {
-               .start = UART1_BASE_ADDR,
-               .end = UART1_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART1,
-               .end = MXC_INT_UART1,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device0 = {
-       .name = "imx-uart",
-       .id = 0,
-       .resource = uart0,
-       .num_resources = ARRAY_SIZE(uart0),
-};
-
-static struct resource uart1[] = {
-       {
-               .start = UART2_BASE_ADDR,
-               .end = UART2_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART2,
-               .end = MXC_INT_UART2,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device1 = {
-       .name = "imx-uart",
-       .id = 1,
-       .resource = uart1,
-       .num_resources = ARRAY_SIZE(uart1),
-};
-
-static struct resource uart2[] = {
-       {
-               .start = UART3_BASE_ADDR,
-               .end = UART3_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART3,
-               .end = MXC_INT_UART3,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device2 = {
-       .name = "imx-uart",
-       .id = 2,
-       .resource = uart2,
-       .num_resources = ARRAY_SIZE(uart2),
-};
-
-#ifdef CONFIG_ARCH_MX31
-static struct resource uart3[] = {
-       {
-               .start = UART4_BASE_ADDR,
-               .end = UART4_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART4,
-               .end = MXC_INT_UART4,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device3 = {
-       .name = "imx-uart",
-       .id = 3,
-       .resource = uart3,
-       .num_resources = ARRAY_SIZE(uart3),
-};
-
-static struct resource uart4[] = {
-       {
-               .start = UART5_BASE_ADDR,
-               .end = UART5_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART5,
-               .end = MXC_INT_UART5,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device4 = {
-       .name = "imx-uart",
-       .id = 4,
-       .resource = uart4,
-       .num_resources = ARRAY_SIZE(uart4),
-};
-#endif /* CONFIG_ARCH_MX31 */
-
 /* GPIO port description */
 static struct mxc_gpio_port imx_gpio_ports[] = {
        {
@@ -147,7 +49,7 @@ static struct mxc_gpio_port imx_gpio_ports[] = {
        }
 };
 
-int __init mxc_register_gpios(void)
+int __init imx3x_register_gpios(void)
 {
        return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 }
@@ -167,82 +69,6 @@ struct platform_device mxc_w1_master_device = {
        .resource = mxc_w1_master_resources,
 };
 
-static struct resource mxc_nand_resources[] = {
-       {
-               .start  = 0, /* runtime dependent */
-               .end    = 0,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = MXC_INT_NANDFC,
-               .end    = MXC_INT_NANDFC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_nand_device = {
-       .name = "mxc_nand",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_nand_resources),
-       .resource = mxc_nand_resources,
-};
-
-static struct resource mxc_i2c0_resources[] = {
-       {
-               .start = I2C_BASE_ADDR,
-               .end = I2C_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_I2C,
-               .end = MXC_INT_I2C,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_i2c_device0 = {
-       .name = "imx-i2c",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_i2c0_resources),
-       .resource = mxc_i2c0_resources,
-};
-
-static struct resource mxc_i2c1_resources[] = {
-       {
-               .start = I2C2_BASE_ADDR,
-               .end = I2C2_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_I2C2,
-               .end = MXC_INT_I2C2,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_i2c_device1 = {
-       .name = "imx-i2c",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_i2c1_resources),
-       .resource = mxc_i2c1_resources,
-};
-
-static struct resource mxc_i2c2_resources[] = {
-       {
-               .start = I2C3_BASE_ADDR,
-               .end = I2C3_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_I2C3,
-               .end = MXC_INT_I2C3,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_i2c_device2 = {
-       .name = "imx-i2c",
-       .id = 2,
-       .num_resources = ARRAY_SIZE(mxc_i2c2_resources),
-       .resource = mxc_i2c2_resources,
-};
-
 #ifdef CONFIG_ARCH_MX31
 static struct resource mxcsdhc0_resources[] = {
        {
@@ -455,68 +281,7 @@ struct platform_device mxc_usbh2 = {
        .num_resources = ARRAY_SIZE(mxc_usbh2_resources),
 };
 
-/*
- * SPI master controller
- * 3 channels
- */
-static struct resource mxc_spi_0_resources[] = {
-       {
-              .start = CSPI1_BASE_ADDR,
-              .end = CSPI1_BASE_ADDR + SZ_4K - 1,
-              .flags = IORESOURCE_MEM,
-       }, {
-              .start = MXC_INT_CSPI1,
-              .end = MXC_INT_CSPI1,
-              .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource mxc_spi_1_resources[] = {
-       {
-               .start = CSPI2_BASE_ADDR,
-               .end = CSPI2_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_CSPI2,
-               .end = MXC_INT_CSPI2,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource mxc_spi_2_resources[] = {
-       {
-               .start = CSPI3_BASE_ADDR,
-               .end = CSPI3_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_CSPI3,
-               .end = MXC_INT_CSPI3,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_spi_device0 = {
-       .name = "spi_imx",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_spi_0_resources),
-       .resource = mxc_spi_0_resources,
-};
-
-struct platform_device mxc_spi_device1 = {
-       .name = "spi_imx",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_spi_1_resources),
-       .resource = mxc_spi_1_resources,
-};
-
-struct platform_device mxc_spi_device2 = {
-       .name = "spi_imx",
-       .id = 2,
-       .num_resources = ARRAY_SIZE(mxc_spi_2_resources),
-       .resource = mxc_spi_2_resources,
-};
-
-#ifdef CONFIG_ARCH_MX35
+#if defined(CONFIG_ARCH_MX35)
 static struct resource mxc_fec_resources[] = {
        {
                .start  = MXC_FEC_BASE_ADDR,
@@ -628,16 +393,15 @@ struct platform_device imx_kpp_device = {
 
 static int __init mx3_devices_init(void)
 {
+#if defined(CONFIG_ARCH_MX31)
        if (cpu_is_mx31()) {
-               mxc_nand_resources[0].start = MX31_NFC_BASE_ADDR;
-               mxc_nand_resources[0].end = MX31_NFC_BASE_ADDR + 0xfff;
                imx_wdt_resources[0].start = MX31_WDOG_BASE_ADDR;
                imx_wdt_resources[0].end = MX31_WDOG_BASE_ADDR + 0x3fff;
                mxc_register_device(&mxc_rnga_device, NULL);
        }
+#endif
+#if defined(CONFIG_ARCH_MX35)
        if (cpu_is_mx35()) {
-               mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
-               mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0x1fff;
                otg_resources[0].start = MX35_OTG_BASE_ADDR;
                otg_resources[0].end = MX35_OTG_BASE_ADDR + 0x1ff;
                otg_resources[1].start = MXC_INT_USBOTG;
@@ -653,6 +417,7 @@ static int __init mx3_devices_init(void)
                imx_wdt_resources[0].start = MX35_WDOG_BASE_ADDR;
                imx_wdt_resources[0].end = MX35_WDOG_BASE_ADDR + 0x3fff;
        }
+#endif
 
        return 0;
 }
index 2c3c8646a29ef701c3872483ddf44901332b4858..e5535234839f5e1ae8159d0513e8bf9c0952d7c7 100644 (file)
@@ -1,14 +1,4 @@
-
-extern struct platform_device mxc_uart_device0;
-extern struct platform_device mxc_uart_device1;
-extern struct platform_device mxc_uart_device2;
-extern struct platform_device mxc_uart_device3;
-extern struct platform_device mxc_uart_device4;
 extern struct platform_device mxc_w1_master_device;
-extern struct platform_device mxc_nand_device;
-extern struct platform_device mxc_i2c_device0;
-extern struct platform_device mxc_i2c_device1;
-extern struct platform_device mxc_i2c_device2;
 extern struct platform_device mx3_ipu;
 extern struct platform_device mx3_fb;
 extern struct platform_device mx3_camera;
@@ -20,9 +10,6 @@ extern struct platform_device mxc_otg_host;
 extern struct platform_device mxc_usbh1;
 extern struct platform_device mxc_usbh2;
 extern struct platform_device mxc_rnga_device;
-extern struct platform_device mxc_spi_device0;
-extern struct platform_device mxc_spi_device1;
-extern struct platform_device mxc_spi_device2;
 extern struct platform_device imx_ssi_device0;
 extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_ssi_device1;
diff --git a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
new file mode 100644 (file)
index 0000000..1dc5004
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
+ *
+ * Based on pcm970-baseboard.c which is :
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <video/platform_lcd.h>
+#include <linux/i2c.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx35.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+#include <mach/audmux.h>
+#include <mach/ssi.h>
+
+#include "devices-imx35.h"
+#include "devices.h"
+
+static const struct fb_videomode fb_modedb[] = {
+       {
+               .name           = "CMO_QVGA",
+               .refresh        = 60,
+               .xres           = 320,
+               .yres           = 240,
+               .pixclock       = KHZ2PICOS(6500),
+               .left_margin    = 68,
+               .right_margin   = 20,
+               .upper_margin   = 15,
+               .lower_margin   = 4,
+               .hsync_len      = 30,
+               .vsync_len      = 3,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       },
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .name           = "CMO_QVGA",
+       .mode           = fb_modedb,
+       .num_modes      = ARRAY_SIZE(fb_modedb),
+};
+
+static struct pad_desc eukrea_mbimxsd_pads[] = {
+       /* LCD */
+       MX35_PAD_LD0__IPU_DISPB_DAT_0,
+       MX35_PAD_LD1__IPU_DISPB_DAT_1,
+       MX35_PAD_LD2__IPU_DISPB_DAT_2,
+       MX35_PAD_LD3__IPU_DISPB_DAT_3,
+       MX35_PAD_LD4__IPU_DISPB_DAT_4,
+       MX35_PAD_LD5__IPU_DISPB_DAT_5,
+       MX35_PAD_LD6__IPU_DISPB_DAT_6,
+       MX35_PAD_LD7__IPU_DISPB_DAT_7,
+       MX35_PAD_LD8__IPU_DISPB_DAT_8,
+       MX35_PAD_LD9__IPU_DISPB_DAT_9,
+       MX35_PAD_LD10__IPU_DISPB_DAT_10,
+       MX35_PAD_LD11__IPU_DISPB_DAT_11,
+       MX35_PAD_LD12__IPU_DISPB_DAT_12,
+       MX35_PAD_LD13__IPU_DISPB_DAT_13,
+       MX35_PAD_LD14__IPU_DISPB_DAT_14,
+       MX35_PAD_LD15__IPU_DISPB_DAT_15,
+       MX35_PAD_LD16__IPU_DISPB_DAT_16,
+       MX35_PAD_LD17__IPU_DISPB_DAT_17,
+       MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC,
+       MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK,
+       MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY,
+       MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC,
+       /* Backlight */
+       MX35_PAD_CONTRAST__IPU_DISPB_CONTR,
+       /* LCD_PWR */
+       MX35_PAD_D3_CLS__GPIO1_4,
+       /* LED */
+       MX35_PAD_LD23__GPIO3_29,
+       /* SWITCH */
+       MX35_PAD_LD19__GPIO3_25,
+       /* UART2 */
+       MX35_PAD_CTS2__UART2_CTS,
+       MX35_PAD_RTS2__UART2_RTS,
+       MX35_PAD_TXD2__UART2_TXD_MUX,
+       MX35_PAD_RXD2__UART2_RXD_MUX,
+       /* I2S */
+       MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS,
+       MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
+       MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
+       MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+};
+
+#define GPIO_LED1      (2 * 32 + 29)
+#define GPIO_SWITCH1   (2 * 32 + 25)
+#define GPIO_LCDPWR    (4)
+
+static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd,
+                                  unsigned int power)
+{
+       if (power)
+               gpio_direction_output(GPIO_LCDPWR, 1);
+       else
+               gpio_direction_output(GPIO_LCDPWR, 0);
+}
+
+static struct plat_lcd_data eukrea_mbimxsd_lcd_power_data = {
+       .set_power              = eukrea_mbimxsd_lcd_power_set,
+};
+
+static struct platform_device eukrea_mbimxsd_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.platform_data      = &eukrea_mbimxsd_lcd_power_data,
+};
+
+static struct gpio_led eukrea_mbimxsd_leds[] = {
+       {
+               .name                   = "led1",
+               .default_trigger        = "heartbeat",
+               .active_low             = 1,
+               .gpio                   = GPIO_LED1,
+       },
+};
+
+static struct gpio_led_platform_data eukrea_mbimxsd_led_info = {
+       .leds           = eukrea_mbimxsd_leds,
+       .num_leds       = ARRAY_SIZE(eukrea_mbimxsd_leds),
+};
+
+static struct platform_device eukrea_mbimxsd_leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &eukrea_mbimxsd_led_info,
+       },
+};
+
+static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
+       {
+               .gpio           = GPIO_SWITCH1,
+               .code           = BTN_0,
+               .desc           = "BP1",
+               .active_low     = 1,
+               .wakeup         = 1,
+       },
+};
+
+static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+       .buttons        = eukrea_mbimxsd_gpio_buttons,
+       .nbuttons       = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
+};
+
+static struct platform_device eukrea_mbimxsd_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &eukrea_mbimxsd_button_data,
+       }
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &eukrea_mbimxsd_leds_gpio,
+       &eukrea_mbimxsd_button_device,
+       &eukrea_mbimxsd_lcd_powerdev,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       },
+};
+
+struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = {
+       .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
+};
+
+/*
+ * system init for baseboard usage. Will be called by cpuimx35 init.
+ *
+ * Add platform devices present on this baseboard and init
+ * them from CPU side as far as required to use them later on
+ */
+void __init eukrea_mbimxsd_baseboard_init(void)
+{
+       if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
+                       ARRAY_SIZE(eukrea_mbimxsd_pads)))
+               printk(KERN_ERR "error setting mbimxsd pads !\n");
+
+#if defined(CONFIG_SND_SOC_EUKREA_TLV320)
+       /* SSI unit master I2S codec connected to SSI_AUD4 */
+       mxc_audmux_v2_configure_port(0,
+                       MXC_AUDMUX_V2_PTCR_SYN |
+                       MXC_AUDMUX_V2_PTCR_TFSDIR |
+                       MXC_AUDMUX_V2_PTCR_TFSEL(3) |
+                       MXC_AUDMUX_V2_PTCR_TCLKDIR |
+                       MXC_AUDMUX_V2_PTCR_TCSEL(3),
+                       MXC_AUDMUX_V2_PDCR_RXDSEL(3)
+       );
+       mxc_audmux_v2_configure_port(3,
+                       MXC_AUDMUX_V2_PTCR_SYN,
+                       MXC_AUDMUX_V2_PDCR_RXDSEL(0)
+       );
+#endif
+
+       imx35_add_imx_uart1(&uart_pdata);
+       mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+       mxc_register_device(&mx3_fb, &mx3fb_pdata);
+
+       mxc_register_device(&imx_ssi_device0, &eukrea_mbimxsd_ssi_pdata);
+
+       gpio_request(GPIO_LED1, "LED1");
+       gpio_direction_output(GPIO_LED1, 1);
+       gpio_free(GPIO_LED1);
+
+       gpio_request(GPIO_SWITCH1, "SWITCH1");
+       gpio_direction_input(GPIO_SWITCH1);
+       gpio_free(GPIO_SWITCH1);
+
+       gpio_request(GPIO_LCDPWR, "LCDPWR");
+       gpio_direction_output(GPIO_LCDPWR, 1);
+       gpio_free(GPIO_SWITCH1);
+
+       i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
+                               ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
+
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
index 5f72ec91af2d62c97acbdff70fbccd4988c292b5..96aadcadb4ff094b1b5eeaaebc502b68cd87a370 100644 (file)
 #include <asm/mach/map.h>
 
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
-#include <mach/board-armadillo5x0.h>
 #include <mach/mmc.h>
 #include <mach/ipu.h>
 #include <mach/mx3fb.h>
-#include <mach/mxc_nand.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 #include "crm_regs.h"
 
@@ -301,7 +299,8 @@ static struct platform_device armadillo5x0_button_device = {
 /*
  * NAND Flash
  */
-static struct mxc_nand_platform_data armadillo5x0_nand_flash_pdata = {
+static const struct mxc_nand_platform_data
+armadillo5x0_nand_board_info __initconst = {
        .width          = 1,
        .hw_ecc         = 1,
 };
@@ -493,13 +492,12 @@ static struct platform_device armadillo5x0_smc911x_device = {
 };
 
 /* UART device data */
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
 static struct platform_device *devices[] __initdata = {
        &armadillo5x0_smc911x_device,
-       &mxc_i2c_device1,
        &armadillo5x0_button_device,
 };
 
@@ -512,10 +510,11 @@ static void __init armadillo5x0_init(void)
                        ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0");
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
+       imx31_add_imx_i2c1(NULL);
 
        /* Register UART */
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
+       imx31_add_imx_uart1(&uart_pdata);
 
        /* SMSC9118 IRQ pin */
        gpio_direction_input(MX31_PIN_GPIO1_0);
@@ -532,7 +531,7 @@ static void __init armadillo5x0_init(void)
                            &armadillo5x0_nor_flash_pdata);
 
        /* Register NAND Flash */
-       mxc_register_device(&mxc_nand_device, &armadillo5x0_nand_flash_pdata);
+       imx31_add_mxc_nand(&armadillo5x0_nand_board_info);
 
        /* set NAND page size to 2k if not configured via boot mode pins */
        __raw_writel(__raw_readl(MXC_CCM_RCSR) | (1 << 30), MXC_CCM_RCSR);
diff --git a/arch/arm/mach-mx3/mach-cpuimx35.c b/arch/arm/mach-mx3/mach-cpuimx35.c
new file mode 100644 (file)
index 0000000..63f970f
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
+ * Copyright (C) 2009 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/memory.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/eukrea-baseboards.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx35.h>
+#include <mach/mxc_nand.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
+
+#include "devices-imx35.h"
+#include "devices.h"
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static const struct imxi2c_platform_data
+eukrea_cpuimx35_i2c0_data __initconst = {
+       .bitrate = 50000,
+};
+
+#define TSC2007_IRQGPIO                (2 * 32 + 2)
+static int ts_get_pendown_state(void)
+{
+       int val = 0;
+       gpio_free(TSC2007_IRQGPIO);
+       gpio_request(TSC2007_IRQGPIO, NULL);
+       gpio_direction_input(TSC2007_IRQGPIO);
+
+       val = gpio_get_value(TSC2007_IRQGPIO);
+
+       gpio_free(TSC2007_IRQGPIO);
+       gpio_request(TSC2007_IRQGPIO, NULL);
+
+       return val ? 0 : 1;
+}
+
+static int ts_init(void)
+{
+       gpio_request(TSC2007_IRQGPIO, NULL);
+       return 0;
+}
+
+static struct tsc2007_platform_data tsc2007_info = {
+       .model                  = 2007,
+       .x_plate_ohms           = 180,
+       .get_pendown_state      = ts_get_pendown_state,
+       .init_platform_hw       = ts_init,
+};
+
+static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pcf8563", 0x51),
+       }, {
+               I2C_BOARD_INFO("tsc2007", 0x48),
+               .type           = "tsc2007",
+               .platform_data  = &tsc2007_info,
+               .irq            = gpio_to_irq(TSC2007_IRQGPIO),
+       },
+};
+
+static struct platform_device *devices[] __initdata = {
+       &mxc_fec_device,
+       &imx_wdt_device0,
+};
+
+static struct pad_desc eukrea_cpuimx35_pads[] = {
+       /* UART1 */
+       MX35_PAD_CTS1__UART1_CTS,
+       MX35_PAD_RTS1__UART1_RTS,
+       MX35_PAD_TXD1__UART1_TXD_MUX,
+       MX35_PAD_RXD1__UART1_RXD_MUX,
+       /* FEC */
+       MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
+       MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
+       MX35_PAD_FEC_RX_DV__FEC_RX_DV,
+       MX35_PAD_FEC_COL__FEC_COL,
+       MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
+       MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
+       MX35_PAD_FEC_TX_EN__FEC_TX_EN,
+       MX35_PAD_FEC_MDC__FEC_MDC,
+       MX35_PAD_FEC_MDIO__FEC_MDIO,
+       MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
+       MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
+       MX35_PAD_FEC_CRS__FEC_CRS,
+       MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
+       MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
+       MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
+       MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
+       MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
+       MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+       /* I2C1 */
+       MX35_PAD_I2C1_CLK__I2C1_SCL,
+       MX35_PAD_I2C1_DAT__I2C1_SDA,
+       /* TSC2007 IRQ */
+       MX35_PAD_ATA_DA2__GPIO3_2,
+};
+
+static const struct mxc_nand_platform_data
+eukrea_cpuimx35_nand_board_info __initconst = {
+       .width          = 1,
+       .hw_ecc         = 1,
+       .flash_bbt      = 1,
+};
+
+static struct mxc_usbh_platform_data otg_pdata = {
+       .portsc = MXC_EHCI_MODE_UTMI,
+       .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
+};
+
+static struct mxc_usbh_platform_data usbh1_pdata = {
+       .portsc = MXC_EHCI_MODE_SERIAL,
+       .flags  = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
+                 MXC_EHCI_IPPUE_DOWN,
+};
+
+static struct fsl_usb2_platform_data otg_device_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_UTMI,
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx35_otg_mode(char *options)
+{
+       if (!strcmp(options, "host"))
+               otg_mode_host = 1;
+       else if (!strcmp(options, "device"))
+               otg_mode_host = 0;
+       else
+               pr_info("otg_mode neither \"host\" nor \"device\". "
+                       "Defaulting to device\n");
+       return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx35_otg_mode);
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads,
+                       ARRAY_SIZE(eukrea_cpuimx35_pads));
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       imx35_add_imx_uart0(&uart_pdata);
+       imx35_add_mxc_nand(&eukrea_cpuimx35_nand_board_info);
+
+       i2c_register_board_info(0, eukrea_cpuimx35_i2c_devices,
+                       ARRAY_SIZE(eukrea_cpuimx35_i2c_devices));
+       imx35_add_imx_i2c0(&eukrea_cpuimx35_i2c0_data);
+
+#if defined(CONFIG_USB_ULPI)
+       if (otg_mode_host) {
+               otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+                               USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+               mxc_register_device(&mxc_otg_host, &otg_pdata);
+       }
+       mxc_register_device(&mxc_usbh1, &usbh1_pdata);
+#endif
+       if (!otg_mode_host)
+               mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
+
+#ifdef CONFIG_MACH_EUKREA_MBIMXSD_BASEBOARD
+       eukrea_mbimxsd_baseboard_init();
+#endif
+}
+
+static void __init eukrea_cpuimx35_timer_init(void)
+{
+       mx35_clocks_init();
+}
+
+struct sys_timer eukrea_cpuimx35_timer = {
+       .init   = eukrea_cpuimx35_timer_init,
+};
+
+MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35")
+       /* Maintainer: Eukrea Electromatique */
+       .phys_io        = MX35_AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = MX3x_PHYS_OFFSET + 0x100,
+       .map_io         = mx35_map_io,
+       .init_irq       = mx35_init_irq,
+       .init_machine   = mxc_board_init,
+       .timer          = &eukrea_cpuimx35_timer,
+MACHINE_END
index f085d5d1a6de7c560d42fba0809b29d73a04a6e9..5b23e416d6c704c904385895f4bbf82dabfba56e 100644 (file)
  * 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/gpio.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
-#include <mach/board-kzmarm11.h>
 #include <mach/clock.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/memory.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 #define KZM_ARM11_IO_ADDRESS(x) (                                      \
        IMX_IO_ADDRESS(x, MX31_CS5) ?:                                  \
        MX31_IO_ADDRESS(x))
 
+/*
+ *  KZM-ARM11-01 Board Control Registers on FPGA
+ */
+#define KZM_ARM11_CTL1         (MX31_CS4_BASE_ADDR + 0x1000)
+#define KZM_ARM11_CTL2         (MX31_CS4_BASE_ADDR + 0x1001)
+#define KZM_ARM11_RSW1         (MX31_CS4_BASE_ADDR + 0x1002)
+#define KZM_ARM11_BACK_LIGHT   (MX31_CS4_BASE_ADDR + 0x1004)
+#define KZM_ARM11_FPGA_REV     (MX31_CS4_BASE_ADDR + 0x1008)
+#define KZM_ARM11_7SEG_LED     (MX31_CS4_BASE_ADDR + 0x1010)
+#define KZM_ARM11_LEDS         (MX31_CS4_BASE_ADDR + 0x1020)
+#define KZM_ARM11_DIPSW2       (MX31_CS4_BASE_ADDR + 0x1003)
+
+/*
+ * External UART for touch panel on FPGA
+ */
+#define KZM_ARM11_16550                (MX31_CS4_BASE_ADDR + 0x1050)
+
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
 /*
  * KZM-ARM11-01 has an external UART on FPGA
@@ -173,15 +185,14 @@ static inline int kzm_init_smsc9118(void)
 #endif
 
 #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
 static void __init kzm_init_imx_uart(void)
 {
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
+       imx31_add_imx_uart1(&uart_pdata);
 }
 #else
 static inline void kzm_init_imx_uart(void)
index 58e57291b79d876fb6bdf04fe6da2020c36d9e1b..6fe69e124d30faa27d23a239ba903f0a76cb1c15 100644 (file)
  * 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>
@@ -22,7 +18,6 @@
 #include <linux/clk.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
-#include <linux/smsc911x.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mc13783.h>
 #include <linux/spi/spi.h>
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <mach/common.h>
-#include <mach/board-mx31_3ds.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
-#include <mach/mxc_nand.h>
-#include <mach/spi.h>
+#include <mach/3ds_debugboard.h>
+
+#include "devices-imx31.h"
 #include "devices.h"
 
-/*!
- * @file mx31_3ds.c
- *
- * @brief This file contains the board-specific initialization routines.
- *
- * @ingroup System
+/* Definitions for components on the Debug board */
+
+/* Base address of CPLD controller on the Debug board */
+#define DEBUG_BASE_ADDRESS             CS5_IO_ADDRESS(MX3x_CS5_BASE_ADDR)
+
+/* LAN9217 ethernet base address */
+#define LAN9217_BASE_ADDR              MX3x_CS5_BASE_ADDR
+
+/* CPLD config and interrupt base address */
+#define CPLD_ADDR                      (DEBUG_BASE_ADDRESS + 0x20000)
+
+/* status, interrupt */
+#define CPLD_INT_STATUS_REG            (CPLD_ADDR + 0x10)
+#define CPLD_INT_MASK_REG              (CPLD_ADDR + 0x38)
+#define CPLD_INT_RESET_REG             (CPLD_ADDR + 0x20)
+/* magic word for debug CPLD */
+#define CPLD_MAGIC_NUMBER1_REG         (CPLD_ADDR + 0x40)
+#define CPLD_MAGIC_NUMBER2_REG         (CPLD_ADDR + 0x48)
+/* CPLD code version */
+#define CPLD_CODE_VER_REG              (CPLD_ADDR + 0x50)
+/* magic word for debug CPLD */
+#define CPLD_MAGIC_NUMBER3_REG         (CPLD_ADDR + 0x58)
+
+/* CPLD IRQ line for external uart, external ethernet etc */
+#define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
+
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
+#define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
+
+#define EXPIO_INT_ENET         (MXC_EXP_IO_BASE + 0)
+
+#define MXC_MAX_EXP_IO_LINES   16
+
+/*
+ * This file contains the board-specific initialization routines.
  */
 
 static int mx31_3ds_pins[] = {
@@ -145,7 +168,7 @@ static int spi1_internal_chipselect[] = {
        MXC_SPI_CS(2),
 };
 
-static struct spi_imx_master spi1_pdata = {
+static const struct spi_imx_master spi1_pdata __initconst = {
        .chipselect     = spi1_internal_chipselect,
        .num_chipselect = ARRAY_SIZE(spi1_internal_chipselect),
 };
@@ -165,7 +188,8 @@ static struct spi_board_info mx31_3ds_spi_devs[] __initdata = {
 /*
  * NAND Flash
  */
-static struct mxc_nand_platform_data imx31_3ds_nand_flash_pdata = {
+static const struct mxc_nand_platform_data
+mx31_3ds_nand_board_info __initconst = {
        .width          = 1,
        .hw_ecc         = 1,
 #ifdef MACH_MX31_3DS_MXC_NAND_USE_BBT
@@ -182,8 +206,10 @@ static struct mxc_nand_platform_data imx31_3ds_nand_flash_pdata = {
 
 #define USBOTG_RST_B IOMUX_TO_GPIO(MX31_PIN_USB_PWR)
 
-static void mx31_3ds_usbotg_init(void)
+static int mx31_3ds_usbotg_init(void)
 {
+       int err;
+
        mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG);
        mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG);
        mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG);
@@ -197,10 +223,25 @@ static void mx31_3ds_usbotg_init(void)
        mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG);
        mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG);
 
-       gpio_request(USBOTG_RST_B, "otgusb-reset");
-       gpio_direction_output(USBOTG_RST_B, 0);
+       err = gpio_request(USBOTG_RST_B, "otgusb-reset");
+       if (err) {
+               pr_err("Failed to request the USB OTG reset gpio\n");
+               return err;
+       }
+
+       err = gpio_direction_output(USBOTG_RST_B, 0);
+       if (err) {
+               pr_err("Failed to drive the USB OTG reset gpio\n");
+               goto usbotg_free_reset;
+       }
+
        mdelay(1);
        gpio_set_value(USBOTG_RST_B, 1);
+       return 0;
+
+usbotg_free_reset:
+       gpio_free(USBOTG_RST_B);
+       return err;
 }
 
 static struct fsl_usb2_platform_data usbotg_pdata = {
@@ -208,178 +249,16 @@ static struct fsl_usb2_platform_data usbotg_pdata = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-/*
- * Support for the SMSC9217 on the Debug board.
- */
-
-static struct smsc911x_platform_config smsc911x_config = {
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
-       .flags          = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-};
-
-static struct resource smsc911x_resources[] = {
-       {
-               .start          = LAN9217_BASE_ADDR,
-               .end            = LAN9217_BASE_ADDR + 0xff,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = EXPIO_INT_ENET,
-               .end            = EXPIO_INT_ENET,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device smsc911x_device = {
-       .name           = "smsc911x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(smsc911x_resources),
-       .resource       = smsc911x_resources,
-       .dev            = {
-               .platform_data = &smsc911x_config,
-       },
-};
-
-/*
- * Routines for the CPLD on the debug board. It contains a CPLD handling
- * LEDs, switches, interrupts for Ethernet.
- */
-
-static void mx31_3ds_expio_irq_handler(uint32_t irq, struct irq_desc *desc)
-{
-       uint32_t imr_val;
-       uint32_t int_valid;
-       uint32_t expio_irq;
-
-       imr_val = __raw_readw(CPLD_INT_MASK_REG);
-       int_valid = __raw_readw(CPLD_INT_STATUS_REG) & ~imr_val;
-
-       expio_irq = MXC_EXP_IO_BASE;
-       for (; int_valid != 0; int_valid >>= 1, expio_irq++) {
-               if ((int_valid & 1) == 0)
-                       continue;
-               generic_handle_irq(expio_irq);
-       }
-}
-
-/*
- * Disable an expio pin's interrupt by setting the bit in the imr.
- * @param irq           an expio virtual irq number
- */
-static void expio_mask_irq(uint32_t irq)
-{
-       uint16_t reg;
-       uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
-
-       /* mask the interrupt */
-       reg = __raw_readw(CPLD_INT_MASK_REG);
-       reg |= 1 << expio;
-       __raw_writew(reg, CPLD_INT_MASK_REG);
-}
-
-/*
- * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr.
- * @param irq           an expanded io virtual irq number
- */
-static void expio_ack_irq(uint32_t irq)
-{
-       uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
-
-       /* clear the interrupt status */
-       __raw_writew(1 << expio, CPLD_INT_RESET_REG);
-       __raw_writew(0, CPLD_INT_RESET_REG);
-       /* mask the interrupt */
-       expio_mask_irq(irq);
-}
-
-/*
- * Enable a expio pin's interrupt by clearing the bit in the imr.
- * @param irq           a expio virtual irq number
- */
-static void expio_unmask_irq(uint32_t irq)
-{
-       uint16_t reg;
-       uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
-
-       /* unmask the interrupt */
-       reg = __raw_readw(CPLD_INT_MASK_REG);
-       reg &= ~(1 << expio);
-       __raw_writew(reg, CPLD_INT_MASK_REG);
-}
-
-static struct irq_chip expio_irq_chip = {
-       .ack = expio_ack_irq,
-       .mask = expio_mask_irq,
-       .unmask = expio_unmask_irq,
-};
-
-static int __init mx31_3ds_init_expio(void)
-{
-       int i;
-       int ret;
-
-       /* Check if there's a debug board connected */
-       if ((__raw_readw(CPLD_MAGIC_NUMBER1_REG) != 0xAAAA) ||
-           (__raw_readw(CPLD_MAGIC_NUMBER2_REG) != 0x5555) ||
-           (__raw_readw(CPLD_MAGIC_NUMBER3_REG) != 0xCAFE)) {
-               /* No Debug board found */
-               return -ENODEV;
-       }
-
-       pr_info("i.MX31 3DS Debug board detected, rev = 0x%04X\n",
-               __raw_readw(CPLD_CODE_VER_REG));
-
-       /*
-        * Configure INT line as GPIO input
-        */
-       ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1), "sms9217-irq");
-       if (ret)
-               pr_warning("could not get LAN irq gpio\n");
-       else
-               gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1));
-
-       /* Disable the interrupts and clear the status */
-       __raw_writew(0, CPLD_INT_MASK_REG);
-       __raw_writew(0xFFFF, CPLD_INT_RESET_REG);
-       __raw_writew(0, CPLD_INT_RESET_REG);
-       __raw_writew(0x1F, CPLD_INT_MASK_REG);
-       for (i = MXC_EXP_IO_BASE;
-            i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES);
-            i++) {
-               set_irq_chip(i, &expio_irq_chip);
-               set_irq_handler(i, handle_level_irq);
-               set_irq_flags(i, IRQF_VALID);
-       }
-       set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_LOW);
-       set_irq_chained_handler(EXPIO_PARENT_INT, mx31_3ds_expio_irq_handler);
-
-       return 0;
-}
-
-/*
- * This structure defines the MX31 memory map.
- */
-static struct map_desc mx31_3ds_io_desc[] __initdata = {
-       {
-               .virtual = MX31_CS5_BASE_ADDR_VIRT,
-               .pfn = __phys_to_pfn(MX31_CS5_BASE_ADDR),
-               .length = MX31_CS5_SIZE,
-               .type = MT_DEVICE,
-       },
-};
-
 /*
  * Set up static virtual mappings.
  */
 static void __init mx31_3ds_map_io(void)
 {
        mx31_map_io();
-       iotable_init(mx31_3ds_io_desc, ARRAY_SIZE(mx31_3ds_io_desc));
 }
 
 /*!
@@ -390,10 +269,10 @@ static void __init mxc_board_init(void)
        mxc_iomux_setup_multiple_pins(mx31_3ds_pins, ARRAY_SIZE(mx31_3ds_pins),
                                      "mx31_3ds");
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_nand_device, &imx31_3ds_nand_flash_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
+       imx31_add_mxc_nand(&mx31_3ds_nand_board_info);
 
-       mxc_register_device(&mxc_spi_device1, &spi1_pdata);
+       imx31_add_spi_imx0(&spi1_pdata);
        spi_register_board_info(mx31_3ds_spi_devs,
                                                ARRAY_SIZE(mx31_3ds_spi_devs));
 
@@ -402,8 +281,9 @@ static void __init mxc_board_init(void)
        mx31_3ds_usbotg_init();
        mxc_register_device(&mxc_otg_udc_device, &usbotg_pdata);
 
-       if (!mx31_3ds_init_expio())
-               platform_device_register(&smsc911x_device);
+       if (!mxc_expio_init(CS5_BASE_ADDR, EXPIO_PARENT_INT))
+               printk(KERN_WARNING "Init of the debugboard failed, all "
+                                   "devices on the board are unusable.\n");
 }
 
 static void __init mx31_3ds_timer_init(void)
index b3d1a1895c20f4f2eab29d99e832c09fbc096373..94b3e7c4240408451aa08446c9b991ad179be699 100644 (file)
  * 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>
@@ -33,8 +29,6 @@
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <mach/common.h>
-#include <mach/board-mx31ads.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 
 #ifdef CONFIG_MACH_MX31ADS_WM1133_EV1
 #include <linux/mfd/wm8350/pmic.h>
 #endif
 
+#include "devices-imx31.h"
 #include "devices.h"
 
-/*!
- * @file mx31ads.c
- *
- * @brief This file contains the board-specific initialization routines.
- *
- * @ingroup System
+/* Base address of PBC controller */
+#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
+/* Offsets for the PBC Controller register */
+
+/* PBC Board interrupt status register */
+#define PBC_INTSTATUS           0x000016
+
+/* PBC Board interrupt current status register */
+#define PBC_INTCURR_STATUS      0x000018
+
+/* PBC Interrupt mask register set address */
+#define PBC_INTMASK_SET         0x00001A
+
+/* PBC Interrupt mask register clear address */
+#define PBC_INTMASK_CLEAR       0x00001C
+
+/* External UART A */
+#define PBC_SC16C652_UARTA      0x010000
+
+/* External UART B */
+#define PBC_SC16C652_UARTB      0x010010
+
+#define PBC_INTSTATUS_REG      (PBC_INTSTATUS + PBC_BASE_ADDRESS)
+#define PBC_INTMASK_SET_REG    (PBC_INTMASK_SET + PBC_BASE_ADDRESS)
+#define PBC_INTMASK_CLEAR_REG  (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
+#define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
+
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
+#define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
+
+#define EXPIO_INT_XUART_INTA   (MXC_EXP_IO_BASE + 10)
+#define EXPIO_INT_XUART_INTB   (MXC_EXP_IO_BASE + 11)
+
+#define MXC_MAX_EXP_IO_LINES   16
+/*
+ * This file contains the board-specific initialization routines.
  */
 
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
@@ -98,7 +123,7 @@ static inline int mxc_init_extuart(void)
 #endif
 
 #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -112,7 +137,7 @@ static unsigned int uart_pins[] = {
 static inline void mxc_init_imx_uart(void)
 {
        mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), "uart-0");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
 }
 #else /* !SERIAL_IMX */
 static inline void mxc_init_imx_uart(void)
@@ -475,7 +500,7 @@ static void mxc_init_i2c(void)
        mxc_iomux_mode(IOMUX_MODE(MX31_PIN_CSPI2_MOSI, IOMUX_CONFIG_ALT1));
        mxc_iomux_mode(IOMUX_MODE(MX31_PIN_CSPI2_MISO, IOMUX_CONFIG_ALT1));
 
-       mxc_register_device(&mxc_i2c_device1, NULL);
+       imx31_add_imx_i2c1(NULL);
 }
 #else
 static void mxc_init_i2c(void)
index b2c7f512070fe450b710db83da53ce439a2a2bd4..8f66f65e80e2079a3dae7e70ddb2a530960d8f98 100644 (file)
  * 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 <mach/common.h>
 #include <mach/iomux-mx3.h>
 #include <mach/board-mx31lilly.h>
-#include <mach/spi.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 /*
@@ -269,12 +265,12 @@ static int spi_internal_chipselect[] = {
        MXC_SPI_CS(2),
 };
 
-static struct spi_imx_master spi0_pdata = {
+static const struct spi_imx_master spi0_pdata __initconst = {
        .chipselect = spi_internal_chipselect,
        .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
 };
 
-static struct spi_imx_master spi1_pdata = {
+static const struct spi_imx_master spi1_pdata __initconst = {
        .chipselect = spi_internal_chipselect,
        .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
 };
@@ -289,6 +285,7 @@ static struct spi_board_info mc13783_dev __initdata = {
        .bus_num        = 1,
        .chip_select    = 0,
        .platform_data  = &mc13783_pdata,
+       .irq            = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3),
 };
 
 static struct platform_device *devices[] __initdata = {
@@ -331,8 +328,8 @@ static void __init mx31lilly_board_init(void)
        mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS1__SS1, "SPI2_SS1");
        mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS2__SS2, "SPI2_SS2");
 
-       mxc_register_device(&mxc_spi_device0, &spi0_pdata);
-       mxc_register_device(&mxc_spi_device1, &spi1_pdata);
+       imx31_add_spi_imx0(&spi0_pdata);
+       imx31_add_spi_imx1(&spi1_pdata);
        spi_register_board_info(&mc13783_dev, 1);
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
index 2b6d1140087740dbc72c157f47770620432a9575..da236c497d2ae38f2d6f01ca765df1957e1be8a1 100644 (file)
  * 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 <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/board-mx31lite.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/irqs.h>
-#include <mach/mxc_nand.h>
-#include <mach/spi.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 /*
@@ -69,7 +63,8 @@ static unsigned int mx31lite_pins[] = {
        MX31_PIN_CSPI2_SS2__SS2,
 };
 
-static struct mxc_nand_platform_data mx31lite_nand_board_info = {
+static const struct mxc_nand_platform_data
+mx31lite_nand_board_info __initconst  = {
        .width = 1,
        .hw_ecc = 1,
 };
@@ -112,7 +107,7 @@ static int spi_internal_chipselect[] = {
        MXC_SPI_CS(0),
 };
 
-static struct spi_imx_master spi1_pdata = {
+static const struct spi_imx_master spi1_pdata __initconst = {
        .chipselect     = spi_internal_chipselect,
        .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
 };
@@ -253,9 +248,9 @@ static void __init mxc_board_init(void)
 
        /* NOR and NAND flash */
        platform_device_register(&physmap_flash_device);
-       mxc_register_device(&mxc_nand_device, &mx31lite_nand_board_info);
+       imx31_add_mxc_nand(&mx31lite_nand_board_info);
 
-       mxc_register_device(&mxc_spi_device1, &spi1_pdata);
+       imx31_add_spi_imx1(&spi1_pdata);
        spi_register_board_info(&mc13783_spi_dev, 1);
 
 #if defined(CONFIG_USB_ULPI)
index 62b5e40165dfea0692b06c97865f2094d053439d..67776bc61c336cc09dfd2c31f7408a20875e79e9 100644 (file)
  * 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 <mach/board-mx31moboard.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/ipu.h>
-#include <mach/i2c.h>
 #include <mach/mmc.h>
 #include <mach/mxc_ehci.h>
 #include <mach/mx3_camera.h>
 #include <mach/spi.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 static unsigned int moboard_pins[] = {
@@ -130,24 +125,36 @@ static struct platform_device mx31moboard_flash = {
 
 static int moboard_uart0_init(struct platform_device *pdev)
 {
-       gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack");
-       gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
-       return 0;
+       int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack");
+       if (ret)
+               return ret;
+
+       ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
+       if (ret)
+               gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
+
+       return ret;
+}
+
+static void moboard_uart0_exit(struct platform_device *pdev)
+{
+       gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
 }
 
-static struct imxuart_platform_data uart0_pdata = {
+static const struct imxuart_platform_data uart0_pdata __initconst = {
        .init = moboard_uart0_init,
+       .exit = moboard_uart0_exit,
 };
 
-static struct imxuart_platform_data uart4_pdata = {
+static const struct imxuart_platform_data uart4_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct imxi2c_platform_data moboard_i2c0_pdata = {
+static const struct imxi2c_platform_data moboard_i2c0_data __initconst = {
        .bitrate = 400000,
 };
 
-static struct imxi2c_platform_data moboard_i2c1_pdata = {
+static const struct imxi2c_platform_data moboard_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -156,7 +163,7 @@ static int moboard_spi1_cs[] = {
        MXC_SPI_CS(2),
 };
 
-static struct spi_imx_master moboard_spi1_master = {
+static const struct spi_imx_master moboard_spi1_pdata __initconst = {
        .chipselect     = moboard_spi1_cs,
        .num_chipselect = ARRAY_SIZE(moboard_spi1_cs),
 };
@@ -286,7 +293,7 @@ static int moboard_spi2_cs[] = {
        MXC_SPI_CS(1),
 };
 
-static struct spi_imx_master moboard_spi2_master = {
+static const struct spi_imx_master moboard_spi2_pdata __initconst = {
        .chipselect     = moboard_spi2_cs,
        .num_chipselect = ARRAY_SIZE(moboard_spi2_cs),
 };
@@ -499,15 +506,14 @@ static void __init mxc_board_init(void)
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_register_device(&mxc_uart_device0, &uart0_pdata);
-
-       mxc_register_device(&mxc_uart_device4, &uart4_pdata);
+       imx31_add_imx_uart0(&uart0_pdata);
+       imx31_add_imx_uart4(&uart4_pdata);
 
-       mxc_register_device(&mxc_i2c_device0, &moboard_i2c0_pdata);
-       mxc_register_device(&mxc_i2c_device1, &moboard_i2c1_pdata);
+       imx31_add_imx_i2c0(&moboard_i2c0_data);
+       imx31_add_imx_i2c1(&moboard_i2c1_data);
 
-       mxc_register_device(&mxc_spi_device1, &moboard_spi1_master);
-       mxc_register_device(&mxc_spi_device2, &moboard_spi2_master);
+       imx31_add_spi_imx1(&moboard_spi1_pdata);
+       imx31_add_spi_imx2(&moboard_spi2_pdata);
 
        gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3), "pmic-irq");
        gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
similarity index 89%
rename from arch/arm/mach-mx3/mach-mx35pdk.c
rename to arch/arm/mach-mx3/mach-mx35_3ds.c
index bcac84d4dca4b71681626388cd2659edf0b10406..1c30d7212f17901a6703cb33d687ddab926ad3cd 100644 (file)
  * 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 machine is known as:
+ *  - i.MX35 3-Stack Development System
+ *  - i.MX35 Platform Development Kit (i.MX35 PDK)
  */
 
 #include <linux/types.h>
 
 #include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx35.h>
 
+#include "devices-imx35.h"
 #include "devices.h"
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -90,7 +92,7 @@ static void __init mxc_board_init(void)
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx35_add_imx_uart0(&uart_pdata);
 
        mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
index cce41066238338d4c09284835227b0dcd33deca4..8a292dd1a7146311394a90540af4811a60df804f 100644 (file)
  * 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 <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
-#include <mach/board-pcm037.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/i2c.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/ipu.h>
 #include <mach/mmc.h>
 #include <mach/mx3_camera.h>
 #include <mach/mx3fb.h>
-#include <mach/mxc_nand.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 #include "pcm037.h"
 
@@ -225,7 +218,7 @@ static struct platform_device pcm037_flash = {
        .num_resources = 1,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -279,16 +272,17 @@ static struct platform_device pcm037_sram_device = {
        .resource = &pcm038_sram_resource,
 };
 
-static struct mxc_nand_platform_data pcm037_nand_board_info = {
+static const struct mxc_nand_platform_data
+pcm037_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
 
-static struct imxi2c_platform_data pcm037_i2c_1_data = {
+static const struct imxi2c_platform_data pcm037_i2c1_data __initconst = {
        .bitrate = 100000,
 };
 
-static struct imxi2c_platform_data pcm037_i2c_2_data = {
+static const struct imxi2c_platform_data pcm037_i2c2_data __initconst = {
        .bitrate = 20000,
 };
 
@@ -545,6 +539,7 @@ static struct platform_device pcm970_sja1000 = {
        .num_resources = ARRAY_SIZE(pcm970_sja1000_resources),
 };
 
+#if defined(CONFIG_USB_ULPI)
 static struct mxc_usbh_platform_data otg_pdata = {
        .portsc = MXC_EHCI_MODE_ULPI,
        .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
@@ -554,6 +549,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
        .portsc = MXC_EHCI_MODE_ULPI,
        .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
 };
+#endif
 
 static struct fsl_usb2_platform_data otg_device_pdata = {
        .operating_mode = FSL_USB2_DR_DEVICE,
@@ -581,7 +577,6 @@ __setup("otg_mode=", pcm037_otg_mode);
 static void __init mxc_board_init(void)
 {
        int ret;
-       u32 tmp;
 
        mxc_iomux_set_gpr(MUX_PGP_UH2, 1);
 
@@ -614,9 +609,10 @@ static void __init mxc_board_init(void)
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
+       /* XXX: should't this have .flags = 0 (i.e. no RTSCTS) on PCM037_EET? */
+       imx31_add_imx_uart1(&uart_pdata);
+       imx31_add_imx_uart2(&uart_pdata);
 
        mxc_register_device(&mxc_w1_master_device, NULL);
 
@@ -634,10 +630,10 @@ static void __init mxc_board_init(void)
        i2c_register_board_info(1, pcm037_i2c_devices,
                        ARRAY_SIZE(pcm037_i2c_devices));
 
-       mxc_register_device(&mxc_i2c_device1, &pcm037_i2c_1_data);
-       mxc_register_device(&mxc_i2c_device2, &pcm037_i2c_2_data);
+       imx31_add_imx_i2c1(&pcm037_i2c1_data);
+       imx31_add_imx_i2c2(&pcm037_i2c2_data);
 
-       mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
+       imx31_add_mxc_nand(&pcm037_nand_board_info);
        mxc_register_device(&mxcsdhc_device0, &sdhc_pdata);
        mxc_register_device(&mx3_ipu, &mx3_ipu_data);
        mxc_register_device(&mx3_fb, &mx3fb_pdata);
index 8d386000fc40d1f9c161ae1e121ec5a6466cba1e..c8b98218efeec9d32882333faa52c41458ce2f37 100644 (file)
@@ -13,9 +13,6 @@
 #include <linux/spi/spi.h>
 
 #include <mach/common.h>
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
-#include <mach/spi.h>
-#endif
 #include <mach/iomux-mx3.h>
 
 #include <asm/mach-types.h>
@@ -64,7 +61,7 @@ static struct spi_board_info pcm037_spi_dev[] = {
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
 static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)};
 
-struct spi_imx_master pcm037_spi1_master = {
+static const struct spi_imx_master pcm037_spi1_pdata __initconst = {
        .chipselect = pcm037_spi1_cs,
        .num_chipselect = ARRAY_SIZE(pcm037_spi1_cs),
 };
@@ -184,7 +181,7 @@ static int eet_init_devices(void)
        /* SPI */
        spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev));
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
-       mxc_register_device(&mxc_spi_device0, &pcm037_spi1_master);
+       imx35_add_spi_imx0(&pcm037_spi1_pdata);
 #endif
 
        platform_device_register(&pcm037_gpio_keys_device);
index 78d9185a9d4ba7f46937f47ffe893935e897b4bb..47f5311b301a18170fa30c86de22cd0d2b64495b 100644 (file)
  * 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 <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
-#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
-#include <mach/i2c.h>
-#endif
 #include <mach/iomux-mx35.h>
 #include <mach/ipu.h>
 #include <mach/mx3fb.h>
-#include <mach/mxc_nand.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 #include <mach/audmux.h>
 #include <mach/ssi.h>
 
+#include "devices-imx35.h"
 #include "devices.h"
 
 static const struct fb_videomode fb_modedb[] = {
@@ -122,12 +114,12 @@ static struct platform_device pcm043_flash = {
        .num_resources = 1,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
 #if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
-static struct imxi2c_platform_data pcm043_i2c_1_data = {
+static const struct imxi2c_platform_data pcm043_i2c0_data __initconst = {
        .bitrate = 50000,
 };
 
@@ -222,6 +214,9 @@ static struct pad_desc pcm043_pads[] = {
        MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
        MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
        MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+       /* CAN2 */
+       MX35_PAD_TX5_RX0__CAN2_TXCAN,
+       MX35_PAD_TX4_RX1__CAN2_RXCAN,
 };
 
 #define AC97_GPIO_TXFS (1 * 32 + 31)
@@ -304,11 +299,13 @@ static struct imx_ssi_platform_data pcm043_ssi_pdata = {
        .flags = IMX_SSI_USE_AC97,
 };
 
-static struct mxc_nand_platform_data pcm037_nand_board_info = {
+static const struct mxc_nand_platform_data
+pcm037_nand_board_info __initconst = {
        .width = 1,
        .hw_ecc = 1,
 };
 
+#if defined(CONFIG_USB_ULPI)
 static struct mxc_usbh_platform_data otg_pdata = {
        .portsc = MXC_EHCI_MODE_UTMI,
        .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
@@ -319,6 +316,7 @@ static struct mxc_usbh_platform_data usbh1_pdata = {
        .flags  = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
                  MXC_EHCI_IPPUE_DOWN,
 };
+#endif
 
 static struct fsl_usb2_platform_data otg_device_pdata = {
        .operating_mode = FSL_USB2_DR_DEVICE,
@@ -361,17 +359,17 @@ static void __init mxc_board_init(void)
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
+       imx35_add_imx_uart0(&uart_pdata);
+       imx35_add_mxc_nand(&pcm037_nand_board_info);
        mxc_register_device(&imx_ssi_device0, &pcm043_ssi_pdata);
 
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+       imx35_add_imx_uart1(&uart_pdata);
 
 #if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
        i2c_register_board_info(0, pcm043_i2c_devices,
                        ARRAY_SIZE(pcm043_i2c_devices));
 
-       mxc_register_device(&mxc_i2c_device0, &pcm043_i2c_1_data);
+       imx35_add_imx_i2c0(&pcm043_i2c0_data);
 #endif
 
        mxc_register_device(&mx3_ipu, &mx3_ipu_data);
@@ -390,6 +388,7 @@ static void __init mxc_board_init(void)
        if (!otg_mode_host)
                mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
 
+       imx35_add_flexcan1(NULL);
 }
 
 static void __init pcm043_timer_init(void)
index e5b5b8323a1793aad3115e4694a8e9bd149155f5..d44ac70222a592246e643b31f8572fcdaf846544 100644 (file)
  * 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>
@@ -34,9 +30,9 @@
 #include <mach/common.h>
 #include <asm/page.h>
 #include <asm/setup.h>
-#include <mach/board-qong.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+
+#include "devices-imx31.h"
 #include "devices.h"
 
 /* FPGA defines */
@@ -62,7 +58,7 @@
  * This file contains the board-specific initialization routines.
  */
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -73,11 +69,11 @@ static int uart_pins[] = {
        MX31_PIN_RXD1__RXD1
 };
 
-static inline void mxc_init_imx_uart(void)
+static inline void __init mxc_init_imx_uart(void)
 {
        mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins),
                        "uart-0");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
 }
 
 static struct resource dnet_resources[] = {
@@ -116,7 +112,7 @@ static struct physmap_flash_data qong_flash_data = {
 
 static struct resource qong_flash_resource = {
        .start = MX31_CS0_BASE_ADDR,
-       .end = MX31_CS0_BASE_ADDR + QONG_NOR_SIZE - 1,
+       .end = MX31_CS0_BASE_ADDR + SZ_128M - 1,
        .flags = IORESOURCE_MEM,
 };
 
index 6858a4f9806cd69f3f0ffe95641d87d342cdd899..20e48c0195c4f8533c7d43113f0ce3965c0ef143 100644 (file)
  * 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/mm.h>
@@ -97,9 +93,12 @@ void __init mx35_map_io(void)
 }
 #endif
 
+int imx3x_register_gpios(void);
+
 void __init mx31_init_irq(void)
 {
        mxc_init_irq(IO_ADDRESS(AVIC_BASE_ADDR));
+       imx3x_register_gpios();
 }
 
 void __init mx35_init_irq(void)
index 7aebd74a12e8c075b3d5dadde345e9c4fea91752..827fd3c802012d7135fbca269456dbf12968d5d1 100644 (file)
  * 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 <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/board-mx31lilly.h>
 #include <mach/mmc.h>
 #include <mach/mx3fb.h>
 #include <mach/ipu.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 /*
@@ -96,7 +92,7 @@ static unsigned int lilly_db_board_pins[] __initdata = {
 };
 
 /* UART */
-static struct imxuart_platform_data uart_pdata __initdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -217,9 +213,9 @@ void __init mx31lilly_db_init(void)
        mxc_iomux_setup_multiple_pins(lilly_db_board_pins,
                                        ARRAY_SIZE(lilly_db_board_pins),
                                        "development board pins");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
+       imx31_add_imx_uart1(&uart_pdata);
+       imx31_add_imx_uart2(&uart_pdata);
        mxc_register_device(&mxcsdhc_device0, &mmc_pdata);
        mx31lilly_init_fb();
 }
index 5f05bfbec38054187324565e3d421a3da01110c9..7b0e74e275ba77110cf73e3173b20ec438796fdc 100644 (file)
  * 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 <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/board-mx31lite.h>
 #include <mach/mmc.h>
-#include <mach/spi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 /*
@@ -76,7 +71,7 @@ static unsigned int litekit_db_board_pins[] __initdata = {
 };
 
 /* UART */
-static struct imxuart_platform_data uart_pdata __initdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -161,7 +156,7 @@ static int spi_internal_chipselect[] = {
        MXC_SPI_CS(2),
 };
 
-static struct spi_imx_master spi0_pdata = {
+static const struct spi_imx_master spi0_pdata __initconst = {
        .chipselect     = spi_internal_chipselect,
        .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
 };
@@ -201,9 +196,9 @@ void __init mx31lite_db_init(void)
        mxc_iomux_setup_multiple_pins(litekit_db_board_pins,
                                        ARRAY_SIZE(litekit_db_board_pins),
                                        "development board pins");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx31_add_imx_uart0(&uart_pdata);
        mxc_register_device(&mxcsdhc_device0, &mmc_pdata);
-       mxc_register_device(&mxc_spi_device0, &spi0_pdata);
+       imx31_add_spi_imx0(&spi0_pdata);
        platform_device_register(&litekit_led_device);
        mxc_register_device(&imx_wdt_device0, NULL);
        mxc_register_device(&imx_rtc_device0, NULL);
index 582299cb2c08be52c6d0cbd9f8c010d123fca33e..fc395a7a8599e78bf2c2096c523e50a0d0fb28aa 100644 (file)
  * 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/gpio.h>
 #include <linux/usb/otg.h>
 
 #include <mach/common.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/hardware.h>
 #include <mach/mmc.h>
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 static unsigned int devboard_pins[] = {
@@ -56,7 +52,7 @@ static unsigned int devboard_pins[] = {
        MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -230,7 +226,7 @@ void __init mx31moboard_devboard_init(void)
        mxc_iomux_setup_multiple_pins(devboard_pins, ARRAY_SIZE(devboard_pins),
                "devboard");
 
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+       imx31_add_imx_uart1(&uart_pdata);
 
        mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
 
index 4930f8c27e661fd5c8612c0369d7e79779f1cf7d..0551eb39d97eec32f7694538838eae418940da80 100644 (file)
  * 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>
index 293eea6d9d97cbd9ffb5cdcbed1409ab685e6a31..40c3e7564cb61c43d77cbd1b01793262e6552eca 100644 (file)
  * 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>
@@ -30,7 +26,6 @@
 
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/board-mx31moboard.h>
 #include <mach/mxc_ehci.h>
@@ -38,6 +33,7 @@
 
 #include <media/soc_camera.h>
 
+#include "devices-imx31.h"
 #include "devices.h"
 
 static unsigned int smartbot_pins[] = {
@@ -59,7 +55,7 @@ static unsigned int smartbot_pins[] = {
        MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -183,8 +179,7 @@ void __init mx31moboard_smartbot_init(int board)
        mxc_iomux_setup_multiple_pins(smartbot_pins, ARRAY_SIZE(smartbot_pins),
                "smartbot");
 
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
-
+       imx31_add_imx_uart1(&uart_pdata);
 
        switch (board) {
        case MX31SMARTBOT:
index 1576d51e676c913cad7c5e4c6f5cfc379d7d336f..0848db5dd364dd5bb5b90ae03f3accf6eeb711aa 100644 (file)
@@ -15,4 +15,31 @@ config MACH_MX51_BABBAGE
          u-boot. This includes specific configurations for the board and its
          peripherals.
 
+config MACH_MX51_3DS
+       bool "Support MX51PDK (3DS)"
+       select MXC_DEBUG_BOARD
+       help
+         Include support for MX51PDK (3DS) platform. This includes specific
+         configurations for the board and its peripherals.
+
+config MACH_EUKREA_CPUIMX51
+       bool "Support Eukrea CPUIMX51 module"
+       help
+         Include support for Eukrea CPUIMX51 platform. This includes
+         specific configurations for the module and its peripherals.
+
+choice
+       prompt "Baseboard"
+       depends on MACH_EUKREA_CPUIMX51
+       default MACH_EUKREA_MBIMX51_BASEBOARD
+
+config MACH_EUKREA_MBIMX51_BASEBOARD
+       prompt "Eukrea MBIMX51 development board"
+       bool
+       help
+         This adds board specific devices that can be found on Eukrea's
+         MBIMX51 evaluation board.
+
+endchoice
+
 endif
index bf23f869ef511817f38be14ec7dcf48b3f82263c..86c66e7f52f3dc0855509587703e6972de2c483e 100644 (file)
@@ -6,4 +6,6 @@
 obj-y   := cpu.o mm.o clock-mx51.o devices.o
 
 obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o
-
+obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o
+obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o
+obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-mx5/board-cpuimx51.c
new file mode 100644 (file)
index 0000000..623607a
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *
+ * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
+ *
+ * based on board-mx51_babbage.c which is
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fsl_devices.h>
+
+#include <mach/eukrea-baseboards.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
+#include <mach/mxc_ehci.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "devices.h"
+
+#define CPUIMX51_USBH1_STP     (0*32 + 27)
+#define CPUIMX51_QUARTA_GPIO   (2*32 + 28)
+#define CPUIMX51_QUARTB_GPIO   (2*32 + 25)
+#define CPUIMX51_QUARTC_GPIO   (2*32 + 26)
+#define CPUIMX51_QUARTD_GPIO   (2*32 + 27)
+#define CPUIMX51_QUARTA_IRQ    (MXC_INTERNAL_IRQS + CPUIMX51_QUARTA_GPIO)
+#define CPUIMX51_QUARTB_IRQ    (MXC_INTERNAL_IRQS + CPUIMX51_QUARTB_GPIO)
+#define CPUIMX51_QUARTC_IRQ    (MXC_INTERNAL_IRQS + CPUIMX51_QUARTC_GPIO)
+#define CPUIMX51_QUARTD_IRQ    (MXC_INTERNAL_IRQS + CPUIMX51_QUARTD_GPIO)
+#define CPUIMX51_QUART_XTAL    14745600
+#define CPUIMX51_QUART_REGSHIFT        17
+
+/* USB_CTRL_1 */
+#define MX51_USB_CTRL_1_OFFSET         0x10
+#define MX51_USB_CTRL_UH1_EXT_CLK_EN   (1 << 25)
+
+#define        MX51_USB_PLLDIV_12_MHZ          0x00
+#define        MX51_USB_PLL_DIV_19_2_MHZ       0x01
+#define        MX51_USB_PLL_DIV_24_MHZ         0x02
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x400000),
+               .irq = CPUIMX51_QUARTA_IRQ,
+               .irqflags = IRQF_TRIGGER_HIGH,
+               .uartclk = CPUIMX51_QUART_XTAL,
+               .regshift = CPUIMX51_QUART_REGSHIFT,
+               .iotype = UPIO_MEM,
+               .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+       }, {
+               .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x800000),
+               .irq = CPUIMX51_QUARTB_IRQ,
+               .irqflags = IRQF_TRIGGER_HIGH,
+               .uartclk = CPUIMX51_QUART_XTAL,
+               .regshift = CPUIMX51_QUART_REGSHIFT,
+               .iotype = UPIO_MEM,
+               .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+       }, {
+               .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x1000000),
+               .irq = CPUIMX51_QUARTC_IRQ,
+               .irqflags = IRQF_TRIGGER_HIGH,
+               .uartclk = CPUIMX51_QUART_XTAL,
+               .regshift = CPUIMX51_QUART_REGSHIFT,
+               .iotype = UPIO_MEM,
+               .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+       }, {
+               .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x2000000),
+               .irq = CPUIMX51_QUARTD_IRQ,
+               .irqflags = IRQF_TRIGGER_HIGH,
+               .uartclk = CPUIMX51_QUART_XTAL,
+               .regshift = CPUIMX51_QUART_REGSHIFT,
+               .iotype = UPIO_MEM,
+               .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+       }, {
+       }
+};
+
+static struct platform_device serial_device = {
+       .name = "serial8250",
+       .id = 0,
+       .dev = {
+               .platform_data = serial_platform_data,
+       },
+};
+#endif
+
+static struct platform_device *devices[] __initdata = {
+       &mxc_fec_device,
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+       &serial_device,
+#endif
+};
+
+static struct pad_desc eukrea_cpuimx51_pads[] = {
+       /* UART1 */
+       MX51_PAD_UART1_RXD__UART1_RXD,
+       MX51_PAD_UART1_TXD__UART1_TXD,
+       MX51_PAD_UART1_RTS__UART1_RTS,
+       MX51_PAD_UART1_CTS__UART1_CTS,
+
+       /* I2C2 */
+       MX51_PAD_GPIO_1_2__I2C2_SCL,
+       MX51_PAD_GPIO_1_3__I2C2_SDA,
+       MX51_PAD_NANDF_D10__GPIO_3_30,
+
+       /* QUART IRQ */
+       MX51_PAD_NANDF_D15__GPIO_3_25,
+       MX51_PAD_NANDF_D14__GPIO_3_26,
+       MX51_PAD_NANDF_D13__GPIO_3_27,
+       MX51_PAD_NANDF_D12__GPIO_3_28,
+
+       /* USB HOST1 */
+       MX51_PAD_USBH1_CLK__USBH1_CLK,
+       MX51_PAD_USBH1_DIR__USBH1_DIR,
+       MX51_PAD_USBH1_NXT__USBH1_NXT,
+       MX51_PAD_USBH1_DATA0__USBH1_DATA0,
+       MX51_PAD_USBH1_DATA1__USBH1_DATA1,
+       MX51_PAD_USBH1_DATA2__USBH1_DATA2,
+       MX51_PAD_USBH1_DATA3__USBH1_DATA3,
+       MX51_PAD_USBH1_DATA4__USBH1_DATA4,
+       MX51_PAD_USBH1_DATA5__USBH1_DATA5,
+       MX51_PAD_USBH1_DATA6__USBH1_DATA6,
+       MX51_PAD_USBH1_DATA7__USBH1_DATA7,
+       MX51_PAD_USBH1_STP__USBH1_STP,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct imxi2c_platform_data eukrea_cpuimx51_i2c_data = {
+       .bitrate = 100000,
+};
+
+static struct i2c_board_info eukrea_cpuimx51_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pcf8563", 0x51),
+       },
+};
+
+/* This function is board specific as the bit mask for the plldiv will also
+be different for other Freescale SoCs, thus a common bitmask is not
+possible and cannot get place in /plat-mxc/ehci.c.*/
+static int initialize_otg_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       void __iomem *usbother_base;
+
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+       /* Set the PHY clock to 19.2MHz */
+       v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+       v |= MX51_USB_PLL_DIV_19_2_MHZ;
+       __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static int initialize_usbh1_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       void __iomem *usbother_base;
+
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+       /* The clock for the USBH1 ULPI port will come externally from the PHY. */
+       v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
+       __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+       .init           = initialize_otg_port,
+       .portsc = MXC_EHCI_UTMI_16BIT,
+       .flags  = MXC_EHCI_INTERNAL_PHY,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_UTMI_WIDE,
+};
+
+static struct mxc_usbh_platform_data usbh1_config = {
+       .init           = initialize_usbh1_port,
+       .portsc = MXC_EHCI_MODE_ULPI,
+       .flags  = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx51_otg_mode(char *options)
+{
+       if (!strcmp(options, "host"))
+               otg_mode_host = 1;
+       else if (!strcmp(options, "device"))
+               otg_mode_host = 0;
+       else
+               pr_info("otg_mode neither \"host\" nor \"device\". "
+                       "Defaulting to device\n");
+       return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx51_otg_mode);
+
+/*
+ * Board specific initialization.
+ */
+static void __init eukrea_cpuimx51_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads,
+                                       ARRAY_SIZE(eukrea_cpuimx51_pads));
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       gpio_request(CPUIMX51_QUARTA_GPIO, "quarta_irq");
+       gpio_direction_input(CPUIMX51_QUARTA_GPIO);
+       gpio_free(CPUIMX51_QUARTA_GPIO);
+       gpio_request(CPUIMX51_QUARTB_GPIO, "quartb_irq");
+       gpio_direction_input(CPUIMX51_QUARTB_GPIO);
+       gpio_free(CPUIMX51_QUARTB_GPIO);
+       gpio_request(CPUIMX51_QUARTC_GPIO, "quartc_irq");
+       gpio_direction_input(CPUIMX51_QUARTC_GPIO);
+       gpio_free(CPUIMX51_QUARTC_GPIO);
+       gpio_request(CPUIMX51_QUARTD_GPIO, "quartd_irq");
+       gpio_direction_input(CPUIMX51_QUARTD_GPIO);
+       gpio_free(CPUIMX51_QUARTD_GPIO);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       mxc_register_device(&mxc_i2c_device1, &eukrea_cpuimx51_i2c_data);
+       i2c_register_board_info(1, eukrea_cpuimx51_i2c_devices,
+                               ARRAY_SIZE(eukrea_cpuimx51_i2c_devices));
+
+       if (otg_mode_host)
+               mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+       else {
+               initialize_otg_port(NULL);
+               mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata);
+       }
+       mxc_register_device(&mxc_usbh1_device, &usbh1_config);
+
+#ifdef CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD
+       eukrea_mbimx51_baseboard_init();
+#endif
+}
+
+static void __init eukrea_cpuimx51_timer_init(void)
+{
+       mx51_clocks_init(32768, 24000000, 22579200, 0);
+}
+
+static struct sys_timer mxc_timer = {
+       .init   = eukrea_cpuimx51_timer_init,
+};
+
+MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module")
+       /* Maintainer: Eric Bénard <eric@eukrea.com> */
+       .phys_io = MX51_AIPS1_BASE_ADDR,
+       .io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params = PHYS_OFFSET + 0x100,
+       .map_io = mx51_map_io,
+       .init_irq = mx51_init_irq,
+       .init_machine = eukrea_cpuimx51_init,
+       .timer = &mxc_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_3ds.c b/arch/arm/mach-mx5/board-mx51_3ds.c
new file mode 100644 (file)
index 0000000..f95c2fd
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010 Jason Wang <jason77.wang@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/input/matrix_keypad.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx51.h>
+#include <mach/imx-uart.h>
+#include <mach/3ds_debugboard.h>
+
+#include "devices.h"
+
+#define EXPIO_PARENT_INT       (MXC_INTERNAL_IRQS + GPIO_PORTA + 6)
+
+static struct pad_desc mx51_3ds_pads[] = {
+       /* UART1 */
+       MX51_PAD_UART1_RXD__UART1_RXD,
+       MX51_PAD_UART1_TXD__UART1_TXD,
+       MX51_PAD_UART1_RTS__UART1_RTS,
+       MX51_PAD_UART1_CTS__UART1_CTS,
+
+       /* UART2 */
+       MX51_PAD_UART2_RXD__UART2_RXD,
+       MX51_PAD_UART2_TXD__UART2_TXD,
+       MX51_PAD_EIM_D25__UART2_CTS,
+       MX51_PAD_EIM_D26__UART2_RTS,
+
+       /* UART3 */
+       MX51_PAD_UART3_RXD__UART3_RXD,
+       MX51_PAD_UART3_TXD__UART3_TXD,
+       MX51_PAD_EIM_D24__UART3_CTS,
+       MX51_PAD_EIM_D27__UART3_RTS,
+
+       /* CPLD PARENT IRQ PIN */
+       MX51_PAD_GPIO_1_6__GPIO_1_6,
+
+       /* KPP */
+       MX51_PAD_KEY_ROW0__KEY_ROW0,
+       MX51_PAD_KEY_ROW1__KEY_ROW1,
+       MX51_PAD_KEY_ROW2__KEY_ROW2,
+       MX51_PAD_KEY_ROW3__KEY_ROW3,
+       MX51_PAD_KEY_COL0__KEY_COL0,
+       MX51_PAD_KEY_COL1__KEY_COL1,
+       MX51_PAD_KEY_COL2__KEY_COL2,
+       MX51_PAD_KEY_COL3__KEY_COL3,
+       MX51_PAD_KEY_COL4__KEY_COL4,
+       MX51_PAD_KEY_COL5__KEY_COL5,
+};
+
+/* Serial ports */
+#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mxc_init_imx_uart(void)
+{
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+}
+#else /* !SERIAL_IMX */
+static inline void mxc_init_imx_uart(void)
+{
+}
+#endif /* SERIAL_IMX */
+
+#if defined(CONFIG_KEYBOARD_IMX) || defined(CONFIG_KEYBOARD_IMX_MODULE)
+static int mx51_3ds_board_keymap[] = {
+       KEY(0, 0, KEY_1),
+       KEY(0, 1, KEY_2),
+       KEY(0, 2, KEY_3),
+       KEY(0, 3, KEY_F1),
+       KEY(0, 4, KEY_UP),
+       KEY(0, 5, KEY_F2),
+
+       KEY(1, 0, KEY_4),
+       KEY(1, 1, KEY_5),
+       KEY(1, 2, KEY_6),
+       KEY(1, 3, KEY_LEFT),
+       KEY(1, 4, KEY_SELECT),
+       KEY(1, 5, KEY_RIGHT),
+
+       KEY(2, 0, KEY_7),
+       KEY(2, 1, KEY_8),
+       KEY(2, 2, KEY_9),
+       KEY(2, 3, KEY_F3),
+       KEY(2, 4, KEY_DOWN),
+       KEY(2, 5, KEY_F4),
+
+       KEY(3, 0, KEY_0),
+       KEY(3, 1, KEY_OK),
+       KEY(3, 2, KEY_ESC),
+       KEY(3, 3, KEY_ENTER),
+       KEY(3, 4, KEY_MENU),
+       KEY(3, 5, KEY_BACK)
+};
+
+static struct matrix_keymap_data mx51_3ds_map_data = {
+       .keymap         = mx51_3ds_board_keymap,
+       .keymap_size    = ARRAY_SIZE(mx51_3ds_board_keymap),
+};
+
+static void mxc_init_keypad(void)
+{
+       mxc_register_device(&mxc_keypad_device, &mx51_3ds_map_data);
+}
+#else
+static inline void mxc_init_keypad(void)
+{
+}
+#endif
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(mx51_3ds_pads,
+                                       ARRAY_SIZE(mx51_3ds_pads));
+       mxc_init_imx_uart();
+
+       if (mxc_expio_init(MX51_CS5_BASE_ADDR, EXPIO_PARENT_INT))
+               printk(KERN_WARNING "Init of the debugboard failed, all "
+                                   "devices on the board are unusable.\n");
+
+       mxc_init_keypad();
+}
+
+static void __init mx51_3ds_timer_init(void)
+{
+       mx51_clocks_init(32768, 24000000, 22579200, 0);
+}
+
+static struct sys_timer mxc_timer = {
+       .init   = mx51_3ds_timer_init,
+};
+
+MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
+       /* Maintainer: Freescale Semiconductor, Inc. */
+       .phys_io = MX51_AIPS1_BASE_ADDR,
+       .io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params = PHYS_OFFSET + 0x100,
+       .map_io = mx51_map_io,
+       .init_irq = mx51_init_irq,
+       .init_machine = mxc_board_init,
+       .timer = &mxc_timer,
+MACHINE_END
index ed885f9d7b73d51e0c19e4ba1c227e95f6dbb09e..6e384d92e625d107279c14228964553525aa6c53 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -21,6 +22,7 @@
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/irq.h>
@@ -64,6 +66,18 @@ static struct pad_desc mx51babbage_pads[] = {
        MX51_PAD_EIM_D27__UART3_RTS,
        MX51_PAD_EIM_D24__UART3_CTS,
 
+       /* I2C1 */
+       MX51_PAD_EIM_D16__I2C1_SDA,
+       MX51_PAD_EIM_D19__I2C1_SCL,
+
+       /* I2C2 */
+       MX51_PAD_KEY_COL4__I2C2_SCL,
+       MX51_PAD_KEY_COL5__I2C2_SDA,
+
+       /* HSI2C */
+       MX51_PAD_I2C1_CLK__HSI2C_CLK,
+       MX51_PAD_I2C1_DAT__HSI2C_DAT,
+
        /* USB HOST1 */
        MX51_PAD_USBH1_CLK__USBH1_CLK,
        MX51_PAD_USBH1_DIR__USBH1_DIR,
@@ -78,7 +92,7 @@ static struct pad_desc mx51babbage_pads[] = {
        MX51_PAD_USBH1_DATA7__USBH1_DATA7,
 
        /* USB HUB reset line*/
-       MX51_PAD_GPIO_1_7__GPIO1_7,
+       MX51_PAD_GPIO_1_7__GPIO_1_7,
 };
 
 /* Serial ports */
@@ -99,6 +113,14 @@ static inline void mxc_init_imx_uart(void)
 }
 #endif /* SERIAL_IMX */
 
+static struct imxi2c_platform_data babbage_i2c_data = {
+       .bitrate = 100000,
+};
+
+static struct imxi2c_platform_data babbage_hsi2c_data = {
+       .bitrate = 400000,
+};
+
 static int gpio_usbh1_active(void)
 {
        struct pad_desc usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO_1_27;
@@ -230,6 +252,10 @@ static void __init mxc_board_init(void)
        mxc_init_imx_uart();
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
+       mxc_register_device(&mxc_i2c_device0, &babbage_i2c_data);
+       mxc_register_device(&mxc_i2c_device1, &babbage_i2c_data);
+       mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data);
+
        if (otg_mode_host)
                mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
        else {
index d9f612d3370e8849bea8bfb568bc3d0c4f3839ec..6af69def357f92d2f177d19d8fc7bce330ff5666 100644 (file)
@@ -758,6 +758,10 @@ static struct clk gpt_32k_clk = {
        .parent = &ckil_clk,
 };
 
+static struct clk kpp_clk = {
+       .id = 0,
+};
+
 #define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s)    \
        static struct clk name = {                      \
                .id             = i,                    \
@@ -798,6 +802,14 @@ DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
 DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET,
        NULL,  NULL, &ipg_clk, NULL);
 
+/* I2C */
+DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET,
+       NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG10_OFFSET,
+       NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET,
+       NULL, NULL, &ipg_clk, NULL);
+
 /* FEC */
 DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET,
        NULL,  NULL, &ipg_clk, NULL);
@@ -815,12 +827,16 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
        _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
+       _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
+       _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk)
        _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk)
        _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk)
        _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk)
        _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", ahb_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk)
+       _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk)
 };
 
 static void clk_tree_init(void)
index 7130449aacdcff6671cea5fe794a418916bdac34..1920ff4963b211376822d2021d4e4bded6b268f1 100644 (file)
@@ -93,6 +93,64 @@ struct platform_device mxc_fec_device = {
        .resource = mxc_fec_resources,
 };
 
+static struct resource mxc_i2c0_resources[] = {
+       {
+               .start = MX51_I2C1_BASE_ADDR,
+               .end = MX51_I2C1_BASE_ADDR + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MX51_MXC_INT_I2C1,
+               .end = MX51_MXC_INT_I2C1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device mxc_i2c_device0 = {
+       .name = "imx-i2c",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_i2c0_resources),
+       .resource = mxc_i2c0_resources,
+};
+
+static struct resource mxc_i2c1_resources[] = {
+       {
+               .start = MX51_I2C2_BASE_ADDR,
+               .end = MX51_I2C2_BASE_ADDR + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MX51_MXC_INT_I2C2,
+               .end = MX51_MXC_INT_I2C2,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device mxc_i2c_device1 = {
+       .name = "imx-i2c",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(mxc_i2c1_resources),
+       .resource = mxc_i2c1_resources,
+};
+
+static struct resource mxc_hsi2c_resources[] = {
+       {
+               .start = MX51_HSI2C_DMA_BASE_ADDR,
+               .end = MX51_HSI2C_DMA_BASE_ADDR + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = MX51_MXC_INT_HS_I2C,
+               .end = MX51_MXC_INT_HS_I2C,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device mxc_hsi2c_device = {
+       .name = "imx-i2c",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(mxc_hsi2c_resources),
+       .resource = mxc_hsi2c_resources
+};
+
 static u64 usb_dma_mask = DMA_BIT_MASK(32);
 
 static struct resource usbotg_resources[] = {
@@ -168,34 +226,57 @@ struct platform_device mxc_wdt = {
        .resource = mxc_wdt_resources,
 };
 
+static struct resource mxc_kpp_resources[] = {
+       {
+               .start = MX51_MXC_INT_KPP,
+               .end = MX51_MXC_INT_KPP,
+               .flags = IORESOURCE_IRQ,
+       } , {
+               .start = MX51_KPP_BASE_ADDR,
+               .end = MX51_KPP_BASE_ADDR + 0x8 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mxc_keypad_device = {
+       .name = "imx-keypad",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_kpp_resources),
+       .resource = mxc_kpp_resources,
+};
+
 static struct mxc_gpio_port mxc_gpio_ports[] = {
        {
                .chip.label = "gpio-0",
                .base = MX51_IO_ADDRESS(MX51_GPIO1_BASE_ADDR),
                .irq = MX51_MXC_INT_GPIO1_LOW,
+               .irq_high = MX51_MXC_INT_GPIO1_HIGH,
                .virtual_irq_start = MXC_GPIO_IRQ_START
        },
        {
                .chip.label = "gpio-1",
                .base = MX51_IO_ADDRESS(MX51_GPIO2_BASE_ADDR),
                .irq = MX51_MXC_INT_GPIO2_LOW,
+               .irq_high = MX51_MXC_INT_GPIO2_HIGH,
                .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1
        },
        {
                .chip.label = "gpio-2",
                .base = MX51_IO_ADDRESS(MX51_GPIO3_BASE_ADDR),
                .irq = MX51_MXC_INT_GPIO3_LOW,
+               .irq_high = MX51_MXC_INT_GPIO3_HIGH,
                .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2
        },
        {
                .chip.label = "gpio-3",
                .base = MX51_IO_ADDRESS(MX51_GPIO4_BASE_ADDR),
                .irq = MX51_MXC_INT_GPIO4_LOW,
+               .irq_high = MX51_MXC_INT_GPIO4_HIGH,
                .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3
        },
 };
 
-int __init mxc_register_gpios(void)
+int __init imx51_register_gpios(void)
 {
        return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports));
 }
index c879ae71cd5b03e2995b3cee1d45f550d857ca47..e509cfaad1d466b4209fd36a5b01d9b4464a3d1a 100644 (file)
@@ -6,3 +6,7 @@ extern struct platform_device mxc_usbdr_host_device;
 extern struct platform_device mxc_usbh1_device;
 extern struct platform_device mxc_usbdr_udc_device;
 extern struct platform_device mxc_wdt;
+extern struct platform_device mxc_i2c_device0;
+extern struct platform_device mxc_i2c_device1;
+extern struct platform_device mxc_hsi2c_device;
+extern struct platform_device mxc_keypad_device;
diff --git a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
new file mode 100644 (file)
index 0000000..ffa93d1
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ *
+ * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c/tsc2007.h>
+#include <linux/leds.h>
+#include <linux/input/matrix_keypad.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx51.h>
+
+#include <asm/mach/arch.h>
+
+#include "devices.h"
+
+#define MBIMX51_TSC2007_GPIO   (2*32 + 30)
+#define MBIMX51_TSC2007_IRQ    (MXC_INTERNAL_IRQS + MBIMX51_TSC2007_GPIO)
+#define MBIMX51_LED0           (2*32 + 5)
+#define MBIMX51_LED1           (2*32 + 6)
+#define MBIMX51_LED2           (2*32 + 7)
+#define MBIMX51_LED3           (2*32 + 8)
+
+static struct gpio_led mbimx51_leds[] = {
+       {
+               .name                   = "led0",
+               .default_trigger        = "heartbeat",
+               .active_low             = 1,
+               .gpio                   = MBIMX51_LED0,
+       },
+       {
+               .name                   = "led1",
+               .default_trigger        = "nand-disk",
+               .active_low             = 1,
+               .gpio                   = MBIMX51_LED1,
+       },
+       {
+               .name                   = "led2",
+               .default_trigger        = "mmc0",
+               .active_low             = 1,
+               .gpio                   = MBIMX51_LED2,
+       },
+       {
+               .name                   = "led3",
+               .default_trigger        = "default-on",
+               .active_low             = 1,
+               .gpio                   = MBIMX51_LED3,
+       },
+};
+
+static struct gpio_led_platform_data mbimx51_leds_info = {
+       .leds           = mbimx51_leds,
+       .num_leds       = ARRAY_SIZE(mbimx51_leds),
+};
+
+static struct platform_device mbimx51_leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &mbimx51_leds_info,
+       },
+};
+
+static struct platform_device *devices[] __initdata = {
+       &mbimx51_leds_gpio,
+};
+
+static struct pad_desc mbimx51_pads[] = {
+       /* UART2 */
+       MX51_PAD_UART2_RXD__UART2_RXD,
+       MX51_PAD_UART2_TXD__UART2_TXD,
+
+       /* UART3 */
+       MX51_PAD_UART3_RXD__UART3_RXD,
+       MX51_PAD_UART3_TXD__UART3_TXD,
+       MX51_PAD_KEY_COL4__UART3_RTS,
+       MX51_PAD_KEY_COL5__UART3_CTS,
+
+       /* TSC2007 IRQ */
+       MX51_PAD_NANDF_D10__GPIO_3_30,
+
+       /* LEDS */
+       MX51_PAD_DISPB2_SER_DIN__GPIO_3_5,
+       MX51_PAD_DISPB2_SER_DIO__GPIO_3_6,
+       MX51_PAD_DISPB2_SER_CLK__GPIO_3_7,
+       MX51_PAD_DISPB2_SER_RS__GPIO_3_8,
+
+       /* KPP */
+       MX51_PAD_KEY_ROW0__KEY_ROW0,
+       MX51_PAD_KEY_ROW1__KEY_ROW1,
+       MX51_PAD_KEY_ROW2__KEY_ROW2,
+       MX51_PAD_KEY_ROW3__KEY_ROW3,
+       MX51_PAD_KEY_COL0__KEY_COL0,
+       MX51_PAD_KEY_COL1__KEY_COL1,
+       MX51_PAD_KEY_COL2__KEY_COL2,
+       MX51_PAD_KEY_COL3__KEY_COL3,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static int mbimx51_keymap[] = {
+       KEY(0, 0, KEY_1),
+       KEY(0, 1, KEY_2),
+       KEY(0, 2, KEY_3),
+       KEY(0, 3, KEY_UP),
+
+       KEY(1, 0, KEY_4),
+       KEY(1, 1, KEY_5),
+       KEY(1, 2, KEY_6),
+       KEY(1, 3, KEY_LEFT),
+
+       KEY(2, 0, KEY_7),
+       KEY(2, 1, KEY_8),
+       KEY(2, 2, KEY_9),
+       KEY(2, 3, KEY_RIGHT),
+
+       KEY(3, 0, KEY_0),
+       KEY(3, 1, KEY_DOWN),
+       KEY(3, 2, KEY_ESC),
+       KEY(3, 3, KEY_ENTER),
+};
+
+static struct matrix_keymap_data mbimx51_map_data = {
+       .keymap         = mbimx51_keymap,
+       .keymap_size    = ARRAY_SIZE(mbimx51_keymap),
+};
+
+static int tsc2007_get_pendown_state(void)
+{
+       return !gpio_get_value(MBIMX51_TSC2007_GPIO);
+}
+
+struct tsc2007_platform_data tsc2007_data = {
+       .model = 2007,
+       .x_plate_ohms = 180,
+       .get_pendown_state = tsc2007_get_pendown_state,
+};
+
+static struct i2c_board_info mbimx51_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("tsc2007", 0x48),
+               .irq  = MBIMX51_TSC2007_IRQ,
+               .platform_data = &tsc2007_data,
+       },
+};
+
+/*
+ * baseboard initialization.
+ */
+void __init eukrea_mbimx51_baseboard_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(mbimx51_pads,
+                                       ARRAY_SIZE(mbimx51_pads));
+
+       mxc_register_device(&mxc_uart_device1, NULL);
+       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+
+       gpio_request(MBIMX51_LED0, "LED0");
+       gpio_direction_output(MBIMX51_LED0, 1);
+       gpio_free(MBIMX51_LED0);
+       gpio_request(MBIMX51_LED1, "LED1");
+       gpio_direction_output(MBIMX51_LED1, 1);
+       gpio_free(MBIMX51_LED1);
+       gpio_request(MBIMX51_LED2, "LED2");
+       gpio_direction_output(MBIMX51_LED2, 1);
+       gpio_free(MBIMX51_LED2);
+       gpio_request(MBIMX51_LED3, "LED3");
+       gpio_direction_output(MBIMX51_LED3, 1);
+       gpio_free(MBIMX51_LED3);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       mxc_register_device(&mxc_keypad_device, &mbimx51_map_data);
+
+       gpio_request(MBIMX51_TSC2007_GPIO, "tsc2007_irq");
+       gpio_direction_input(MBIMX51_TSC2007_GPIO);
+       set_irq_type(MBIMX51_TSC2007_IRQ, IRQF_TRIGGER_FALLING);
+       i2c_register_board_info(1, mbimx51_i2c_devices,
+                               ARRAY_SIZE(mbimx51_i2c_devices));
+}
index b7677ef80cc4388a4c414c4b7c8e1269137227a6..bc3f30db8d9a0f2df94debe9bf556000f58b0e91 100644 (file)
@@ -65,6 +65,8 @@ void __init mx51_map_io(void)
        iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
 
+int imx51_register_gpios(void);
+
 void __init mx51_init_irq(void)
 {
        unsigned long tzic_addr;
@@ -80,4 +82,5 @@ void __init mx51_init_irq(void)
                panic("unable to map TZIC interrupt controller\n");
 
        tzic_init_irq(tzic_virt);
+       imx51_register_gpios();
 }
index ce4f5905818982580bae7b24fca1a6ea0a67573d..b989baccd67507f76b5aa8dcc5fb7d6a2f67029f 100644 (file)
  * 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 _ARCH_ARM_MACH_MXC91231_CRM_REGS_H_
index 353bd977b393b3e87e21dd83c866776a69479d0b..027af4f0d18aed1a40c97f448f43daa2028efc32 100644 (file)
@@ -135,7 +135,7 @@ static struct mxc_gpio_port mxc_gpio_ports[] = {
        },
 };
 
-int __init mxc_register_gpios(void)
+int __init mxc91231_register_gpios(void)
 {
        return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports));
 }
index 6becda3ff331ddf4196dc8a6667cbd543decd07e..aeccfd755fee6a9af9307a31a766a31fd091f7d5 100644 (file)
  * 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/mm.h>
@@ -88,7 +83,10 @@ void __init mxc91231_map_io(void)
        iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
 
+int mxc91231_register_gpios(void);
+
 void __init mxc91231_init_irq(void)
 {
+       mxc91231_register_gpios();
        mxc_init_irq(MXC91231_IO_ADDRESS(MXC91231_AVIC_BASE_ADDR));
 }
index f035f4185274160757e11d32377509defbdfb1b7..89f793adf77643093c9e465c35447553102ae295 100644 (file)
@@ -53,6 +53,10 @@ static struct clk clk_default;
        }
 
 static struct clk_lookup lookups[] = {
+       {
+               .con_id         = "apb_pclk",
+               .clk            = &clk_default,
+       },
        CLK(&clk_24, "mtu0"),
        CLK(&clk_24, "mtu1"),
        CLK(&clk_48, "uart0"),
index fdd1dd53fa9ceddcc5738687b36215d31c3b8ca0..0a9d61d2d2293f8b51c32eb82cd4bea5ada9e6d9 100644 (file)
@@ -301,6 +301,7 @@ MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = ams_delta_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = ams_delta_init_irq,
        .init_machine   = ams_delta_init,
        .timer          = &omap_timer,
index 096f2ed102cbe5aa8fff6a3632022f999776c51d..059bac60b35ae7a3d5d5a59a7e481e549989ae2d 100644 (file)
@@ -378,6 +378,7 @@ MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_fsample_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_fsample_init_irq,
        .init_machine   = omap_fsample_init,
        .timer          = &omap_timer,
index e1195a3467b86106a60c258a429c664ca818569e..7a65684d2a15b52064a7afee5be0926b5d8e0ffd 100644 (file)
@@ -98,6 +98,7 @@ MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_generic_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_generic_init_irq,
        .init_machine   = omap_generic_init,
        .timer          = &omap_timer,
index d1100e4f65aca736c6113643c1310cff4bc2a9b4..68b2beda8b99c8ef9e5261e7a658d0968bb7d27b 100644 (file)
@@ -467,6 +467,7 @@ MACHINE_START(OMAP_H2, "TI-H2")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = h2_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = h2_init_irq,
        .init_machine   = h2_init,
        .timer          = &omap_timer,
index a53ab8297d25eb05185b433d310ab2dd415290bf..0b0825fe6751aea72a6ee39e490ab75bf087fd79 100644 (file)
@@ -437,6 +437,7 @@ MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = h3_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = h3_init_irq,
        .init_machine   = h3_init,
        .timer          = &omap_timer,
index 8e313b4b99a9d91145201f1d2e28a4a022a7f151..d70a4f0923f53278858692e2bf48637dbb495a4b 100644 (file)
@@ -304,6 +304,7 @@ MACHINE_START(HERALD, "HTC Herald")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = htcherald_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = htcherald_init_irq,
        .init_machine   = htcherald_init,
        .timer          = &omap_timer,
index 5d12fd35681b24041695fd3a324bb5a8f2d226bc..91064b37859a131e1d71250d941ebb4e3844237f 100644 (file)
@@ -463,6 +463,7 @@ MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = innovator_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = innovator_init_irq,
        .init_machine   = innovator_init,
        .timer          = &omap_timer,
index 71e1a3fad0ead110b7947e555af8c652da261695..8c28b10f3dae75b091017600d03c2d1ed67eca07 100644 (file)
@@ -400,6 +400,7 @@ MACHINE_START(NOKIA770, "Nokia 770")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_nokia770_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_nokia770_init_irq,
        .init_machine   = omap_nokia770_init,
        .timer          = &omap_timer,
index 80d862001def595ef2fada032e909a9bcd9aea01..e2a72af30890bbd54850257c3d82df1e5e38339f 100644 (file)
@@ -584,6 +584,7 @@ MACHINE_START(OMAP_OSK, "TI-OSK")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = osk_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = osk_init_irq,
        .init_machine   = osk_init,
        .timer          = &omap_timer,
index 569b4c9085cd8b952f91716ebe7e00984ebe7169..61a2321b97323d200db96f1e6e8ceb73794189ed 100644 (file)
@@ -373,6 +373,7 @@ MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_palmte_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_palmte_init_irq,
        .init_machine   = omap_palmte_init,
        .timer          = &omap_timer,
index 6ad49a2cc1a03af4368628ddef06896786d6c3ae..21c01c6afcc1690faaa3cea3399b085b2e8efc9f 100644 (file)
@@ -321,6 +321,7 @@ MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_palmtt_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_palmtt_init_irq,
        .init_machine   = omap_palmtt_init,
        .timer          = &omap_timer,
index 6641de9257efa047cbf02d94e37506675913c354..f324924515332e956e1eebbda1319b54f9a8a407 100644 (file)
@@ -338,10 +338,12 @@ omap_palmz71_map_io(void)
 }
 
 MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
-       .phys_io = 0xfff00000,
-       .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
-       .boot_params = 0x10000100,.map_io = omap_palmz71_map_io,
-       .init_irq = omap_palmz71_init_irq,
-       .init_machine = omap_palmz71_init,
-       .timer = &omap_timer,
+       .phys_io        = 0xfff00000,
+       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
+       .boot_params    = 0x10000100,
+       .map_io         = omap_palmz71_map_io,
+       .reserve        = omap_reserve,
+       .init_irq       = omap_palmz71_init_irq,
+       .init_machine   = omap_palmz71_init,
+       .timer          = &omap_timer,
 MACHINE_END
index e854d5741c8889daad675ae230bef5848bdcf6fa..8b5ab1fcc405820979ea0e70c2f7a86ed68c17bb 100644 (file)
@@ -339,6 +339,7 @@ MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_perseus2_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_perseus2_init_irq,
        .init_machine   = omap_perseus2_init,
        .timer          = &omap_timer,
index 2fb1e5f8e2ec5c637a992007123842bf7e48d2f3..995566b862bb739c04953e2d3ad94175b494570b 100644 (file)
@@ -423,7 +423,8 @@ MACHINE_START(SX1, "OMAP310 based Siemens SX1")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_sx1_map_io,
-       .init_irq               = omap_sx1_init_irq,
+       .reserve        = omap_reserve,
+       .init_irq       = omap_sx1_init_irq,
        .init_machine   = omap_sx1_init,
        .timer          = &omap_timer,
 MACHINE_END
index 87b9436fe7c0c011972fd24b7da43716a5aad5fd..4c483dc1de5c4fa3ee22f2db095b1b4b4d273e31 100644 (file)
@@ -287,6 +287,7 @@ MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = voiceblue_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = voiceblue_init_irq,
        .init_machine   = voiceblue_init,
        .timer          = &omap_timer,
index d9b8d82530ae165bf18ab272c49ff61a069ae298..0ce3fec2d257c2b6183a4b426608e56679ff556c 100644 (file)
@@ -22,7 +22,6 @@
 
 extern void omap_check_revision(void);
 extern void omap_sram_init(void);
-extern void omapfb_reserve_sdram(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -122,7 +121,6 @@ void __init omap1_map_common_io(void)
 #endif
 
        omap_sram_init();
-       omapfb_reserve_sdram();
 }
 
 /*
index a11a575745e44c5bcab1d1fd7cc202afeedd06ea..42f49f785c93811c8956192287159ed711a07115 100644 (file)
@@ -248,6 +248,7 @@ MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_2430sdp_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_2430sdp_init_irq,
        .init_machine   = omap_2430sdp_init,
        .timer          = &omap_timer,
index f474a80b886733582af7f3dba04929ce02cd561b..dd9c03171a19c3dd0d83c69a9109fb92c18c380c 100644 (file)
@@ -815,6 +815,7 @@ MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_3430sdp_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_3430sdp_init_irq,
        .init_machine   = omap_3430sdp_init,
        .timer          = &omap_timer,
index 504d2bd222fe35ec02bb277f5f87d6af6f18e5e8..57290fb3fcd76d5171c1316b17c944f7df78c3d4 100644 (file)
@@ -108,6 +108,7 @@ MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_sdp_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_sdp_init_irq,
        .init_machine   = omap_sdp_init,
        .timer          = &omap_timer,
index e4a5d66b83b8bbb5e8f1701bbba5a94f825b9703..4bb2c5d151ec9908164e5263ad7a903342e732f6 100644 (file)
@@ -402,6 +402,7 @@ MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_4430sdp_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_4430sdp_init_irq,
        .init_machine   = omap_4430sdp_init,
        .timer          = &omap_timer,
index af383a8769432fd108bc48efedf5e893e93f60fe..7da92defcde04e0604125da51d320f548f91c82e 100644 (file)
@@ -472,6 +472,7 @@ MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
        .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = am3517_evm_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = am3517_evm_init_irq,
        .init_machine   = am3517_evm_init,
        .timer          = &omap_timer,
index aa69fb999748af3698a6950f9549a59c8260f5a7..bd75642aee65d0828ebf7897806662c20b616c54 100644 (file)
@@ -346,6 +346,7 @@ MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_apollon_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_apollon_init_irq,
        .init_machine   = omap_apollon_init,
        .timer          = &omap_timer,
index e679a2cc86c3061031923123c21e4189bf028e8a..bc4c3f807068ee76848370482587e6566aa2f482 100644 (file)
@@ -837,6 +837,7 @@ MACHINE_START(CM_T35, "Compulab CM-T35")
        .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = cm_t35_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = cm_t35_init_irq,
        .init_machine   = cm_t35_init,
        .timer          = &omap_timer,
index 77022b58881670fc38bf3c88840a4b925ae0ff03..922b7464807fb964193b5298d2f2f99d98f6e7fd 100644 (file)
@@ -825,6 +825,7 @@ MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000")
        .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = devkit8000_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = devkit8000_init_irq,
        .init_machine   = devkit8000_init,
        .timer          = &omap_timer,
index 16cc06860670ed7cf22c4a6e1d991d6e76fe3b89..9242902d3a43ccf36670f89daee4a2a5677b11ef 100644 (file)
@@ -59,6 +59,7 @@ MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_generic_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_generic_init_irq,
        .init_machine   = omap_generic_init,
        .timer          = &omap_timer,
index 0665f2c8dc8e894a1e949baf2a273e7bef104159..16703fdb3515e73347bb1bb5c1c556295fbce223 100644 (file)
@@ -378,6 +378,7 @@ MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_h4_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_h4_init_irq,
        .init_machine   = omap_h4_init,
        .timer          = &omap_timer,
index d55c57b761a988e3bb62cc2adeb999709861db2c..759e39d1a702fdc9b84f12a70990e995154bc6d6 100644 (file)
@@ -543,6 +543,7 @@ MACHINE_START(IGEP0020, "IGEP v2 board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = igep2_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = igep2_init_irq,
        .init_machine   = igep2_init,
        .timer          = &omap_timer,
index fefd7e6e97796a9ede0ce8076de96f9ee437fb9d..9cd2669113e49f548375b09260100e9da078cfd1 100644 (file)
@@ -417,6 +417,7 @@ MACHINE_START(OMAP_LDP, "OMAP LDP board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_ldp_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_ldp_init_irq,
        .init_machine   = omap_ldp_init,
        .timer          = &omap_timer,
index 3ccc34ebdcc79c11e021b4c80e9fca550bfea037..2565ff08a2218963d1b0213b75127f764e37ea2b 100644 (file)
@@ -667,6 +667,7 @@ MACHINE_START(NOKIA_N800, "Nokia N800")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = n8x0_init_irq,
        .init_machine   = n8x0_init_machine,
        .timer          = &omap_timer,
@@ -677,6 +678,7 @@ MACHINE_START(NOKIA_N810, "Nokia N810")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = n8x0_init_irq,
        .init_machine   = n8x0_init_machine,
        .timer          = &omap_timer,
@@ -687,6 +689,7 @@ MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = n8x0_init_irq,
        .init_machine   = n8x0_init_machine,
        .timer          = &omap_timer,
index 69b154cdc75dcaa2c46d0a33434cfc7c379fd1fc..0ab0c26db4dd063c99966612ca210c80ec6f3092 100644 (file)
@@ -519,6 +519,7 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_beagle_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap3_beagle_init_irq,
        .init_machine   = omap3_beagle_init,
        .timer          = &omap_timer,
index b952610138121862368aab2296ef30552bdc5528..a3d2e285e116111161939de0c8d2ec689cc5cb8f 100644 (file)
@@ -727,6 +727,7 @@ MACHINE_START(OMAP3EVM, "OMAP3 EVM")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_evm_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap3_evm_init_irq,
        .init_machine   = omap3_evm_init,
        .timer          = &omap_timer,
index db06dc910ba755c6988cc11155c3f047dff3c792..c0f4f12eba549458fefc82124dfd3938f9976efe 100644 (file)
@@ -601,6 +601,7 @@ MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3pandora_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap3pandora_init_irq,
        .init_machine   = omap3pandora_init,
        .timer          = &omap_timer,
index 2f5f8233dd5b8857bcfddb29d178f802fbd1271f..f05b867c585109392708a6bdb37f49392fbc775c 100644 (file)
@@ -571,6 +571,7 @@ MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board")
        .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_touchbook_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap3_touchbook_init_irq,
        .init_machine   = omap3_touchbook_init,
        .timer          = &omap_timer,
index 79ac41400c218039193ab8a3384805d74953797a..87acb2f198ecaedf274b18973f6ca1e99f037d96 100644 (file)
@@ -495,6 +495,7 @@ MACHINE_START(OVERO, "Gumstix Overo")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = overo_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = overo_init_irq,
        .init_machine   = overo_init,
        .timer          = &omap_timer,
index 1b86b5bb87a219bc89d3703131c2d70c28181d04..3bd956f9e19f5bb74588dd28fcae16aa047e55de 100644 (file)
@@ -154,6 +154,7 @@ MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = rx51_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = rx51_init_irq,
        .init_machine   = rx51_init,
        .timer          = &omap_timer,
index 803ef14cbf2d64ca3218e56ce4e48572088fe67f..ffe188cb18e90185f306199bae2b6da0acb71a91 100644 (file)
@@ -95,6 +95,7 @@ MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
        .io_pg_offst    = (ZOOM_UART_VIRT >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_zoom2_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_zoom2_init_irq,
        .init_machine   = omap_zoom2_init,
        .timer          = &omap_timer,
index 33147042485f5f505c7a0906f2b0d94e02a9f460..5b605eba3e7bcf449c9fa62020233e49b8f8ae8a 100644 (file)
@@ -77,6 +77,7 @@ MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
        .io_pg_offst    = (ZOOM_UART_VIRT >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_zoom_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_zoom_init_irq,
        .init_machine   = omap_zoom_init,
        .timer          = &omap_timer,
index 41b155acfca7cf2605202f78ffbe45a84ebf594a..d33744117ce2488067b50c739afd701623beb315 100644 (file)
@@ -3166,6 +3166,10 @@ static struct clk uart4_ick_am35xx = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk dummy_apb_pclk = {
+       .name           = "apb_pclk",
+       .ops            = &clkops_null,
+};
 
 /*
  * clkdev
@@ -3173,6 +3177,7 @@ static struct clk uart4_ick_am35xx = {
 
 /* XXX At some point we should rename this file to clock3xxx_data.c */
 static struct omap_clk omap3xxx_clks[] = {
+       CLK(NULL,       "apb_pclk",     &dummy_apb_pclk,        CK_3XXX),
        CLK(NULL,       "omap_32k_fck", &omap_32k_fck,  CK_3XXX),
        CLK(NULL,       "virt_12m_ck",  &virt_12m_ck,   CK_3XXX),
        CLK(NULL,       "virt_13m_ck",  &virt_13m_ck,   CK_3XXX),
index 3cfb425ea67e86585f66e1595b29e2c28b4d31ea..4e1f53d0b8801cfb799a626d80562d1df0378103 100644 (file)
@@ -33,7 +33,6 @@
 #include <plat/sdrc.h>
 #include <plat/gpmc.h>
 #include <plat/serial.h>
-#include <plat/vram.h>
 
 #include "clock2xxx.h"
 #include "clock3xxx.h"
@@ -241,8 +240,6 @@ static void __init _omap2_map_common_io(void)
 
        omap2_check_revision();
        omap_sram_init();
-       omapfb_reserve_sdram();
-       omap_vram_reserve_sdram();
 }
 
 #ifdef CONFIG_ARCH_OMAP2420
index 905719a677ae31b8be356f356b289569157ec48d..c897e03e413d05eb91c836d0472d9534f71633f7 100644 (file)
@@ -26,6 +26,7 @@ config MACH_KUROBOX_PRO
 config MACH_DNS323
        bool "D-Link DNS-323"
        select I2C_BOARDINFO
+       select PHYLIB
        help
          Say 'Y' here if you want your kernel to support the
          D-Link DNS-323 platform.
index fe0de1698edc95c9e4aedf78aac576d2fc9e69b8..a47100d46a4e88a9f3f41b4d1705ddc397cfe622 100644 (file)
@@ -3,6 +3,10 @@
  *
  * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
  *
+ * Support for HW Rev C1:
+ *
+ * Copyright (C) 2010 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2 of the
@@ -23,6 +27,8 @@
 #include <linux/input.h>
 #include <linux/i2c.h>
 #include <linux/ata_platform.h>
+#include <linux/phy.h>
+#include <linux/marvell_phy.h>
 #include <asm/mach-types.h>
 #include <asm/gpio.h>
 #include <asm/mach/arch.h>
@@ -31,6 +37,7 @@
 #include "common.h"
 #include "mpp.h"
 
+/* Rev A1 and B1 */
 #define DNS323_GPIO_LED_RIGHT_AMBER    1
 #define DNS323_GPIO_LED_LEFT_AMBER     2
 #define DNS323_GPIO_SYSTEM_UP          3
 #define DNS323_GPIO_KEY_POWER          9
 #define DNS323_GPIO_KEY_RESET          10
 
+/* Rev C1 */
+#define DNS323C_GPIO_KEY_POWER         1
+#define DNS323C_GPIO_POWER_OFF         2
+#define DNS323C_GPIO_LED_RIGHT_AMBER   8
+#define DNS323C_GPIO_LED_LEFT_AMBER    9
+#define DNS323C_GPIO_LED_POWER         17
+#define DNS323C_GPIO_FAN_BIT1          18
+#define DNS323C_GPIO_FAN_BIT0          19
+
+/* Exposed to userspace, do not change */
+enum {
+       DNS323_REV_A1,  /* 0 */
+       DNS323_REV_B1,  /* 1 */
+       DNS323_REV_C1,  /* 2 */
+};
+
+
 /****************************************************************************
  * PCI setup
  */
@@ -68,21 +92,12 @@ static struct hw_pci dns323_pci __initdata = {
        .map_irq        = dns323_pci_map_irq,
 };
 
-static int __init dns323_dev_id(void)
-{
-       u32 dev, rev;
-
-       orion5x_pcie_id(&dev, &rev);
-
-       return dev;
-}
-
 static int __init dns323_pci_init(void)
 {
-       /* The 5182 doesn't really use its PCI bus, and initialising PCI
+       /* Rev B1 and C1 doesn't really use its PCI bus, and initialising PCI
         * gets in the way of initialising the SATA controller.
         */
-       if (machine_is_dns323() && dns323_dev_id() != MV88F5182_DEV_ID)
+       if (machine_is_dns323() && system_rev == DNS323_REV_A1)
                pci_common_init(&dns323_pci);
 
        return 0;
@@ -221,7 +236,7 @@ static int __init dns323_read_mac_addr(void)
        }
 
        iounmap(mac_page);
-       printk("DNS323: Found ethernet MAC address: ");
+       printk("DNS-323: Found ethernet MAC address: ");
        for (i = 0; i < 6; i++)
                printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n");
 
@@ -259,12 +274,11 @@ static int dns323_gpio_blink_set(unsigned gpio, int state,
        return 0;
 }
 
-static struct gpio_led dns323_leds[] = {
+static struct gpio_led dns323ab_leds[] = {
        {
                .name = "power:blue",
                .gpio = DNS323_GPIO_LED_POWER2,
-               .default_trigger = "timer",
-               .active_low = 1,
+               .default_trigger = "default-on",
        }, {
                .name = "right:amber",
                .gpio = DNS323_GPIO_LED_RIGHT_AMBER,
@@ -276,9 +290,34 @@ static struct gpio_led dns323_leds[] = {
        },
 };
 
-static struct gpio_led_platform_data dns323_led_data = {
-       .num_leds       = ARRAY_SIZE(dns323_leds),
-       .leds           = dns323_leds,
+
+static struct gpio_led dns323c_leds[] = {
+       {
+               .name = "power:blue",
+               .gpio = DNS323C_GPIO_LED_POWER,
+               .default_trigger = "timer",
+               .active_low = 1,
+       }, {
+               .name = "right:amber",
+               .gpio = DNS323C_GPIO_LED_RIGHT_AMBER,
+               .active_low = 1,
+       }, {
+               .name = "left:amber",
+               .gpio = DNS323C_GPIO_LED_LEFT_AMBER,
+               .active_low = 1,
+       },
+};
+
+
+static struct gpio_led_platform_data dns323ab_led_data = {
+       .num_leds       = ARRAY_SIZE(dns323ab_leds),
+       .leds           = dns323ab_leds,
+       .gpio_blink_set = dns323_gpio_blink_set,
+};
+
+static struct gpio_led_platform_data dns323c_led_data = {
+       .num_leds       = ARRAY_SIZE(dns323c_leds),
+       .leds           = dns323c_leds,
        .gpio_blink_set = dns323_gpio_blink_set,
 };
 
@@ -286,7 +325,7 @@ static struct platform_device dns323_gpio_leds = {
        .name           = "leds-gpio",
        .id             = -1,
        .dev            = {
-               .platform_data  = &dns323_led_data,
+               .platform_data  = &dns323ab_led_data,
        },
 };
 
@@ -294,7 +333,7 @@ static struct platform_device dns323_gpio_leds = {
  * GPIO Attached Keys
  */
 
-static struct gpio_keys_button dns323_buttons[] = {
+static struct gpio_keys_button dns323ab_buttons[] = {
        {
                .code           = KEY_RESTART,
                .gpio           = DNS323_GPIO_KEY_RESET,
@@ -308,9 +347,23 @@ static struct gpio_keys_button dns323_buttons[] = {
        },
 };
 
-static struct gpio_keys_platform_data dns323_button_data = {
-       .buttons        = dns323_buttons,
-       .nbuttons       = ARRAY_SIZE(dns323_buttons),
+static struct gpio_keys_platform_data dns323ab_button_data = {
+       .buttons        = dns323ab_buttons,
+       .nbuttons       = ARRAY_SIZE(dns323ab_buttons),
+};
+
+static struct gpio_keys_button dns323c_buttons[] = {
+       {
+               .code           = KEY_POWER,
+               .gpio           = DNS323C_GPIO_KEY_POWER,
+               .desc           = "Power Button",
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data dns323c_button_data = {
+       .buttons        = dns323c_buttons,
+       .nbuttons       = ARRAY_SIZE(dns323c_buttons),
 };
 
 static struct platform_device dns323_button_device = {
@@ -318,7 +371,7 @@ static struct platform_device dns323_button_device = {
        .id             = -1,
        .num_resources  = 0,
        .dev            = {
-               .platform_data  = &dns323_button_data,
+               .platform_data  = &dns323ab_button_data,
        },
 };
 
@@ -332,7 +385,7 @@ static struct mv_sata_platform_data dns323_sata_data = {
 /****************************************************************************
  * General Setup
  */
-static struct orion5x_mpp_mode dns323_mv88f5181_mpp_modes[] __initdata = {
+static struct orion5x_mpp_mode dns323a_mpp_modes[] __initdata = {
        {  0, MPP_PCIE_RST_OUTn },
        {  1, MPP_GPIO },               /* right amber LED (sata ch0) */
        {  2, MPP_GPIO },               /* left amber LED (sata ch1) */
@@ -356,7 +409,7 @@ static struct orion5x_mpp_mode dns323_mv88f5181_mpp_modes[] __initdata = {
        { -1 },
 };
 
-static struct orion5x_mpp_mode dns323_mv88f5182_mpp_modes[] __initdata = {
+static struct orion5x_mpp_mode dns323b_mpp_modes[] __initdata = {
        {  0, MPP_UNUSED },
        {  1, MPP_GPIO },               /* right amber LED (sata ch0) */
        {  2, MPP_GPIO },               /* left amber LED (sata ch1) */
@@ -380,15 +433,57 @@ static struct orion5x_mpp_mode dns323_mv88f5182_mpp_modes[] __initdata = {
        { -1 },
 };
 
+static struct orion5x_mpp_mode dns323c_mpp_modes[] __initdata = {
+       {  0, MPP_GPIO },               /* ? input */
+       {  1, MPP_GPIO },               /* input power switch (0 = pressed) */
+       {  2, MPP_GPIO },               /* output power off */
+       {  3, MPP_UNUSED },             /* ? output */
+       {  4, MPP_UNUSED },             /* ? output */
+       {  5, MPP_UNUSED },             /* ? output */
+       {  6, MPP_UNUSED },             /* ? output */
+       {  7, MPP_UNUSED },             /* ? output */
+       {  8, MPP_GPIO },               /* i/o right amber LED */
+       {  9, MPP_GPIO },               /* i/o left amber LED */
+       { 10, MPP_GPIO },               /* input */
+       { 11, MPP_UNUSED },
+       { 12, MPP_SATA_LED },
+       { 13, MPP_SATA_LED },
+       { 14, MPP_SATA_LED },
+       { 15, MPP_SATA_LED },
+       { 16, MPP_UNUSED },
+       { 17, MPP_GPIO },               /* power button LED */
+       { 18, MPP_GPIO },               /* fan speed bit 0 */
+       { 19, MPP_GPIO },               /* fan speed bit 1 */
+       { -1 },
+};
+
+/* Rev C1 Fan speed notes:
+ *
+ * The fan is controlled by 2 GPIOs on this board. The settings
+ * of the bits is as follow:
+ *
+ *  GPIO 18    GPIO 19    Fan
+ *
+ *    0          0        stopped
+ *    0          1        low speed
+ *    1          0        high speed
+ *    1          1        don't do that (*)
+ *
+ * (*) I think the two bits control two feed-in resistors into a fixed
+ *     PWN circuit, setting both bits will basically go a 'bit' faster
+ *     than high speed, but d-link doesn't do it and you may get out of
+ *     HW spec so don't do it.
+ */
+
 /*
- * On the DNS-323 the following devices are attached via I2C:
+ * On the DNS-323 A1 and B1 the following devices are attached via I2C:
  *
  *  i2c addr | chip        | description
  *  0x3e     | GMT G760Af  | fan speed PWM controller
  *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
  *  0x68     | ST M41T80   | RTC w/ alarm
  */
-static struct i2c_board_info __initdata dns323_i2c_devices[] = {
+static struct i2c_board_info __initdata dns323ab_i2c_devices[] = {
        {
                I2C_BOARD_INFO("g760a", 0x3e),
        }, {
@@ -398,36 +493,140 @@ static struct i2c_board_info __initdata dns323_i2c_devices[] = {
        },
 };
 
+/*
+ * On the DNS-323 C1 the following devices are attached via I2C:
+ *
+ *  i2c addr | chip        | description
+ *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
+ *  0x68     | ST M41T80   | RTC w/ alarm
+ */
+static struct i2c_board_info __initdata dns323c_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("lm75", 0x48),
+       }, {
+               I2C_BOARD_INFO("m41t80", 0x68),
+       },
+};
+
 /* DNS-323 rev. A specific power off method */
 static void dns323a_power_off(void)
 {
-       pr_info("%s: triggering power-off...\n", __func__);
+       pr_info("DNS-323: Triggering power-off...\n");
        gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
 }
 
 /* DNS-323 rev B specific power off method */
 static void dns323b_power_off(void)
 {
-       pr_info("%s: triggering power-off...\n", __func__);
+       pr_info("DNS-323: Triggering power-off...\n");
        /* Pin has to be changed to 1 and back to 0 to do actual power off. */
        gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
        mdelay(100);
        gpio_set_value(DNS323_GPIO_POWER_OFF, 0);
 }
 
+/* DNS-323 rev. C specific power off method */
+static void dns323c_power_off(void)
+{
+       pr_info("DNS-323: Triggering power-off...\n");
+       gpio_set_value(DNS323C_GPIO_POWER_OFF, 1);
+}
+
+static int dns323c_phy_fixup(struct phy_device *phy)
+{
+       phy->dev_flags |= MARVELL_PHY_M1118_DNS323_LEDS;
+
+       return 0;
+}
+
+static int __init dns323_identify_rev(void)
+{
+       u32 dev, rev, i, reg;
+
+       pr_debug("DNS-323: Identifying board ... \n");
+
+       /* Rev A1 has a 5181 */
+       orion5x_pcie_id(&dev, &rev);
+       if (dev == MV88F5181_DEV_ID) {
+               pr_debug("DNS-323: 5181 found, board is A1\n");
+               return DNS323_REV_A1;
+       }
+       pr_debug("DNS-323: 5182 found, board is B1 or C1, checking PHY...\n");
+
+       /* Rev B1 and C1 both have 5182, let's poke at the eth PHY. This is
+        * a bit gross but we want to do that without links into the eth
+        * driver so let's poke at it directly. We default to rev B1 in
+        * case the accesses fail
+        */
+
+#define ETH_SMI_REG            (ORION5X_ETH_VIRT_BASE + 0x2000 + 0x004)
+#define  SMI_BUSY              0x10000000
+#define  SMI_READ_VALID                0x08000000
+#define  SMI_OPCODE_READ       0x04000000
+#define  SMI_OPCODE_WRITE      0x00000000
+
+       for (i = 0; i < 1000; i++) {
+               reg = readl(ETH_SMI_REG);
+               if (!(reg & SMI_BUSY))
+                       break;
+       }
+       if (i >= 1000) {
+               pr_warning("DNS-323: Timeout accessing PHY, assuming rev B1\n");
+               return DNS323_REV_B1;
+       }
+       writel((3 << 21)        /* phy ID reg */ |
+              (8 << 16)        /* phy addr */ |
+              SMI_OPCODE_READ, ETH_SMI_REG);
+       for (i = 0; i < 1000; i++) {
+               reg = readl(ETH_SMI_REG);
+               if (reg & SMI_READ_VALID)
+                       break;
+       }
+       if (i >= 1000) {
+               pr_warning("DNS-323: Timeout reading PHY, assuming rev B1\n");
+               return DNS323_REV_B1;
+       }
+       pr_debug("DNS-323: Ethernet PHY ID 0x%x\n", reg & 0xffff);
+
+       /* Note: the Marvell tools mask the ID with 0x3f0 before comparison
+        * but I don't see that making a difference here, at least with
+        * any known Marvell PHY ID
+        */
+       switch(reg & 0xfff0) {
+       case 0x0cc0: /* MV88E1111 */
+               return DNS323_REV_B1;
+       case 0x0e10: /* MV88E1118 */
+               return DNS323_REV_C1;
+       default:
+               pr_warning("DNS-323: Unknown PHY ID 0x%04x, assuming rev B1\n",
+                          reg & 0xffff);
+       }
+       return DNS323_REV_B1;
+}
+
 static void __init dns323_init(void)
 {
        /* Setup basic Orion functions. Need to be called early. */
        orion5x_init();
 
+       /* Identify revision */
+       system_rev = dns323_identify_rev();
+       pr_info("DNS-323: Identified HW revision %c1\n", 'A' + system_rev);
+
        /* Just to be tricky, the 5182 has a completely different
         * set of MPP modes to the 5181.
         */
-       if (dns323_dev_id() == MV88F5182_DEV_ID)
-               orion5x_mpp_conf(dns323_mv88f5182_mpp_modes);
-       else {
-               orion5x_mpp_conf(dns323_mv88f5181_mpp_modes);
+       switch(system_rev) {
+       case DNS323_REV_A1:
+               orion5x_mpp_conf(dns323a_mpp_modes);
                writel(0, MPP_DEV_CTRL);                /* DEV_D[31:16] */
+               break;
+       case DNS323_REV_B1:
+               orion5x_mpp_conf(dns323b_mpp_modes);
+               break;
+       case DNS323_REV_C1:
+               orion5x_mpp_conf(dns323c_mpp_modes);
+               break;
        }
 
        /* setup flash mapping
@@ -436,53 +635,96 @@ static void __init dns323_init(void)
        orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE);
        platform_device_register(&dns323_nor_flash);
 
-       /* The 5181 power LED is active low and requires
-        * DNS323_GPIO_LED_POWER1 to also be low.
-        */
-       if (dns323_dev_id() == MV88F5181_DEV_ID) {
-               dns323_leds[0].active_low = 1;
-               gpio_request(DNS323_GPIO_LED_POWER1, "Power Led Enable");
-               gpio_direction_output(DNS323_GPIO_LED_POWER1, 0);
+       /* Sort out LEDs, Buttons and i2c devices */
+       switch(system_rev) {
+       case DNS323_REV_A1:
+               /* The 5181 power LED is active low and requires
+                * DNS323_GPIO_LED_POWER1 to also be low.
+                */
+                dns323ab_leds[0].active_low = 1;
+                gpio_request(DNS323_GPIO_LED_POWER1, "Power Led Enable");
+                gpio_direction_output(DNS323_GPIO_LED_POWER1, 0);
+               /* Fall through */
+       case DNS323_REV_B1:
+               i2c_register_board_info(0, dns323ab_i2c_devices,
+                               ARRAY_SIZE(dns323ab_i2c_devices));
+               break;
+       case DNS323_REV_C1:
+               /* Hookup LEDs & Buttons */
+               dns323_gpio_leds.dev.platform_data = &dns323c_led_data;
+               dns323_button_device.dev.platform_data = &dns323c_button_data;
+
+               /* Hookup i2c devices and fan driver */
+               i2c_register_board_info(0, dns323c_i2c_devices,
+                               ARRAY_SIZE(dns323c_i2c_devices));
+               platform_device_register_simple("dns323c-fan", 0, NULL, 0);
+
+               /* Register fixup for the PHY LEDs */
+               phy_register_fixup_for_uid(MARVELL_PHY_ID_88E1118,
+                                          MARVELL_PHY_ID_MASK,
+                                          dns323c_phy_fixup);
        }
 
        platform_device_register(&dns323_gpio_leds);
-
        platform_device_register(&dns323_button_device);
 
-       i2c_register_board_info(0, dns323_i2c_devices,
-                               ARRAY_SIZE(dns323_i2c_devices));
-
        /*
         * Configure peripherals.
         */
        if (dns323_read_mac_addr() < 0)
-               printk("DNS323: Failed to read MAC address\n");
-
+               printk("DNS-323: Failed to read MAC address\n");
        orion5x_ehci0_init();
        orion5x_eth_init(&dns323_eth_data);
        orion5x_i2c_init();
        orion5x_uart0_init();
 
-       /* The 5182 has its SATA controller on-chip, and needs its own little
-        * init routine.
-        */
-       if (dns323_dev_id() == MV88F5182_DEV_ID)
+       /* Remaining GPIOs */
+       switch(system_rev) {
+       case DNS323_REV_A1:
+               /* Poweroff GPIO */
+               if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
+                   gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
+                       pr_err("DNS-323: failed to setup power-off GPIO\n");
+               pm_power_off = dns323a_power_off;
+               break;
+       case DNS323_REV_B1:
+               /* 5182 built-in SATA init */
                orion5x_sata_init(&dns323_sata_data);
 
-       /* The 5182 has flag to indicate the system is up. Without this flag
-        * set, power LED will flash and cannot be controlled via leds-gpio.
-        */
-       if (dns323_dev_id() == MV88F5182_DEV_ID)
-               gpio_set_value(DNS323_GPIO_SYSTEM_UP, 1);
-
-       /* Register dns323 specific power-off method */
-       if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
-           gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
-               pr_err("DNS323: failed to setup power-off GPIO\n");
-       if (dns323_dev_id() == MV88F5182_DEV_ID)
+               /* The DNS323 rev B1 has flag to indicate the system is up.
+                * Without this flag set, power LED will flash and cannot be
+                * controlled via leds-gpio.
+                */
+               if (gpio_request(DNS323_GPIO_SYSTEM_UP, "SYS_READY") == 0)
+                       gpio_direction_output(DNS323_GPIO_SYSTEM_UP, 1);
+
+               /* Poweroff GPIO */
+               if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
+                   gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
+                       pr_err("DNS-323: failed to setup power-off GPIO\n");
                pm_power_off = dns323b_power_off;
-       else
-               pm_power_off = dns323a_power_off;
+               break;
+       case DNS323_REV_C1:
+               /* 5182 built-in SATA init */
+               orion5x_sata_init(&dns323_sata_data);
+
+               /* Poweroff GPIO */
+               if (gpio_request(DNS323C_GPIO_POWER_OFF, "POWEROFF") != 0 ||
+                   gpio_direction_output(DNS323C_GPIO_POWER_OFF, 0) != 0)
+                       pr_err("DNS-323: failed to setup power-off GPIO\n");
+               pm_power_off = dns323c_power_off;
+
+               /* Now, -this- should theorically be done by the sata_mv driver
+                * once I figure out what's going on there. Maybe the behaviour
+                * of the LEDs should be somewhat passed via the platform_data.
+                * for now, just whack the register and make the LEDs happy
+                *
+                * Note: AFAIK, rev B1 needs the same treatement but I'll let
+                * somebody else test it.
+                */
+               writel(0x5, ORION5X_SATA_VIRT_BASE | 0x2c);
+               break;
+       }
 }
 
 /* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
index 60e734c104584c3765268b310c18e6df37b84937..a1d6e46ab0355fd5e6410ff4449bbcca28427d81 100644 (file)
@@ -25,6 +25,8 @@ static inline void arch_reset(char mode, const char *cmd)
         */
        orion5x_setbits(RSTOUTn_MASK, (1 << 2));
        orion5x_setbits(CPU_SOFT_RESET, 1);
+       mdelay(200);
+       orion5x_clrbits(CPU_SOFT_RESET, 1);
 }
 
 
index 161fc2d6120705b2f4737c5f1980b7631fd089a5..0f3130599770f2a7008d2de009ea09266620e708 100644 (file)
@@ -35,7 +35,7 @@ static int cmx2xx_it8152_irq_gpio;
  * This is really ugly and we need a better way of specifying
  * DMA-capable regions of memory.
  */
-void __init cmx2xx_pci_adjust_zones(int node, unsigned long *zone_size,
+void __init cmx2xx_pci_adjust_zones(unsigned long *zone_size,
        unsigned long *zhole_size)
 {
        unsigned int sz = SZ_64M >> PAGE_SHIFT;
@@ -46,7 +46,7 @@ void __init cmx2xx_pci_adjust_zones(int node, unsigned long *zone_size,
                /*
                 * Only adjust if > 64M on current system
                 */
-               if (node || (zone_size[0] <= sz))
+               if (zone_size[0] <= sz)
                        return;
 
                zone_size[1] = zone_size[0] - sz;
index 51ffa6afb67530e5cde74659319584ac52646593..461ba4080155414d6e64b8d0f61f4dcee49a24fa 100644 (file)
@@ -715,7 +715,6 @@ static void __init fixup_corgi(struct machine_desc *desc,
        sharpsl_save_param();
        mi->nr_banks=1;
        mi->bank[0].start = 0xa0000000;
-       mi->bank[0].node = 0;
        if (machine_is_corgi())
                mi->bank[0].size = (32*1024*1024);
        else
index 96ed13081639598335309b23b992751d27102ea5..a0ab3082a0009d31b3837f1234f6f4175cde6a8b 100644 (file)
@@ -34,7 +34,6 @@ void __init eseries_fixup(struct machine_desc *desc,
 {
        mi->nr_banks=1;
        mi->bank[0].start = 0xa0000000;
-       mi->bank[0].node = 0;
        if (machine_is_e800())
                mi->bank[0].size = (128*1024*1024);
        else
index 890fb90a672f5e957af6f9d75f78425f4d371fd5..c6305c5b8a72c1497ee05aee42d7795b07513c94 100644 (file)
@@ -26,8 +26,7 @@ extern unsigned int get_clk_frequency_khz(int info);
 
 #define SET_BANK(__nr,__start,__size) \
        mi->bank[__nr].start = (__start), \
-       mi->bank[__nr].size = (__size), \
-       mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
+       mi->bank[__nr].size = (__size)
 
 #define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
 
index f626730ee42e11a8071149677b43f55fb85666a7..92361a66b223d9f62243074d26ee534a131cba64 100644 (file)
  */
 #define PHYS_OFFSET    UL(0xa0000000)
 
-/*
- * The nodes are matched with the physical SDRAM banks as follows:
- *
- *     node 0:  0xa0000000-0xa3ffffff  -->  0xc0000000-0xc3ffffff
- *     node 1:  0xa4000000-0xa7ffffff  -->  0xc4000000-0xc7ffffff
- *     node 2:  0xa8000000-0xabffffff  -->  0xc8000000-0xcbffffff
- *     node 3:  0xac000000-0xafffffff  -->  0xcc000000-0xcfffffff
- *
- * This needs a node mem size of 26 bits.
- */
-#define NODE_MEM_SIZE_BITS     26
-
 #if !defined(__ASSEMBLY__) && defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
-void cmx2xx_pci_adjust_zones(int node, unsigned long *size,
-                            unsigned long *holes);
+void cmx2xx_pci_adjust_zones(unsigned long *size, unsigned long *holes);
 
-#define arch_adjust_zones(node, size, holes) \
-       cmx2xx_pci_adjust_zones(node, size, holes)
+#define arch_adjust_zones(size, holes) \
+       cmx2xx_pci_adjust_zones(size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_64M - 1)
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_64M)
index 5305a3993e694b77666920db5e1581a1abb503fc..5e92d84fe50d0805be94a07f583c40ee46f0e6c4 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/memblock.h>
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
 #include <linux/gpio.h>
@@ -396,6 +397,11 @@ static void __init palmt5_udc_init(void)
        }
 }
 
+static void __init palmt5_reserve(void)
+{
+       memblock_reserve(0xa0200000, 0x1000);
+}
+
 static void __init palmt5_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config));
@@ -421,6 +427,7 @@ MACHINE_START(PALMT5, "Palm Tungsten|T5")
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .reserve        = palmt5_reserve,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = palmt5_init
index d8b4469607a1e1794a1775238bddd8c478e99e4a..3d0c9cc2a40648a049a3ccc81a34c5f03f4126de 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/memblock.h>
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
 #include <linux/gpio.h>
@@ -633,6 +634,12 @@ static void __init treo_lcd_power_init(void)
        treo_lcd_screen.pxafb_lcd_power = treo_lcd_power;
 }
 
+static void __init treo_reserve(void)
+{
+       memblock_reserve(0xa0000000, 0x1000);
+       memblock_reserve(0xa2000000, 0x1000);
+}
+
 static void __init treo_init(void)
 {
        pxa_set_ffuart_info(NULL);
@@ -668,6 +675,7 @@ MACHINE_START(TREO680, "Palm Treo 680")
        .io_pg_offst    = io_p2v(0x40000000),
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .reserve        = treo_reserve,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = treo680_init,
@@ -691,6 +699,7 @@ MACHINE_START(CENTRO, "Palm Centro 685")
        .io_pg_offst    = io_p2v(0x40000000),
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .reserve        = treo_reserve,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = centro_init,
index f4abdaafdac4d5c552bd7aa72421b8f8bd97a263..bc2758b54446fc5cc38db451fc70a9ed77d0511a 100644 (file)
@@ -463,7 +463,6 @@ static void __init fixup_poodle(struct machine_desc *desc,
        sharpsl_save_param();
        mi->nr_banks=1;
        mi->bank[0].start = 0xa0000000;
-       mi->bank[0].node = 0;
        mi->bank[0].size = (32*1024*1024);
 }
 
index c1048a35f187e990984a83111110671241ff1f93..51756c723557e8c25eee690aa57e252a1aa08376 100644 (file)
@@ -847,7 +847,6 @@ static void __init fixup_spitz(struct machine_desc *desc,
        sharpsl_save_param();
        mi->nr_banks = 1;
        mi->bank[0].start = 0xa0000000;
-       mi->bank[0].node = 0;
        mi->bank[0].size = (64*1024*1024);
 }
 
index 7512b822c6cac0f1b0473a7ec029a66a45b33030..83cc3a18c2e9a0ded180a0b223f29167b3a290f7 100644 (file)
@@ -948,7 +948,6 @@ static void __init fixup_tosa(struct machine_desc *desc,
        sharpsl_save_param();
        mi->nr_banks=1;
        mi->bank[0].start = 0xa0000000;
-       mi->bank[0].node = 0;
        mi->bank[0].size = (64*1024*1024);
 }
 
index 595be19f8ad5027e29daed72bbe0fb2c5d2d1a04..2fa38df284140e08099739d55305a93e7899ebe3 100644 (file)
@@ -61,12 +61,11 @@ void __iomem *gic_cpu_base_addr;
 /*
  * Adjust the zones if there are restrictions for DMA access.
  */
-void __init realview_adjust_zones(int node, unsigned long *size,
-                                 unsigned long *hole)
+void __init realview_adjust_zones(unsigned long *size, unsigned long *hole)
 {
        unsigned long dma_size = SZ_256M >> PAGE_SHIFT;
 
-       if (!machine_is_realview_pbx() || node || (size[0] <= dma_size))
+       if (!machine_is_realview_pbx() || size[0] <= dma_size)
                return;
 
        size[ZONE_NORMAL] = size[0] - dma_size;
@@ -232,12 +231,27 @@ static unsigned int realview_mmc_status(struct device *dev)
        struct amba_device *adev = container_of(dev, struct amba_device, dev);
        u32 mask;
 
+       if (machine_is_realview_pb1176()) {
+               static bool inserted = false;
+
+               /*
+                * The PB1176 does not have the status register,
+                * assume it is inserted at startup, then invert
+                * for each call so card insertion/removal will
+                * be detected anyway. This will not be called if
+                * GPIO on PL061 is active, which is the proper
+                * way to do this on the PB1176.
+                */
+               inserted = !inserted;
+               return inserted ? 0 : 1;
+       }
+
        if (adev->res.start == REALVIEW_MMCI0_BASE)
                mask = 1;
        else
                mask = 2;
 
-       return !(readl(REALVIEW_SYSMCI) & mask);
+       return readl(REALVIEW_SYSMCI) & mask;
 }
 
 struct mmci_platform_data realview_mmc0_plat_data = {
@@ -300,8 +314,13 @@ static struct clk ref24_clk = {
        .rate   = 24000000,
 };
 
+static struct clk dummy_apb_pclk;
+
 static struct clk_lookup lookups[] = {
-       {       /* UART0 */
+       {       /* Bus clock */
+               .con_id         = "apb_pclk",
+               .clk            = &dummy_apb_pclk,
+       }, {    /* UART0 */
                .dev_id         = "dev:uart0",
                .clk            = &ref24_clk,
        }, {    /* UART1 */
@@ -313,6 +332,12 @@ static struct clk_lookup lookups[] = {
        }, {    /* UART3 */
                .dev_id         = "fpga:uart3",
                .clk            = &ref24_clk,
+       }, {    /* UART3 is on the dev chip in PB1176 */
+               .dev_id         = "dev:uart3",
+               .clk            = &ref24_clk,
+       }, {    /* UART4 only exists in PB1176 */
+               .dev_id         = "fpga:uart4",
+               .clk            = &ref24_clk,
        }, {    /* KMI0 */
                .dev_id         = "fpga:kmi0",
                .clk            = &ref24_clk,
@@ -322,12 +347,15 @@ static struct clk_lookup lookups[] = {
        }, {    /* MMC0 */
                .dev_id         = "fpga:mmc0",
                .clk            = &ref24_clk,
-       }, {    /* EB:CLCD */
+       }, {    /* CLCD is in the PB1176 and EB DevChip */
                .dev_id         = "dev:clcd",
                .clk            = &oscvco_clk,
        }, {    /* PB:CLCD */
                .dev_id         = "issp:clcd",
                .clk            = &oscvco_clk,
+       }, {    /* SSP */
+               .dev_id         = "dev:ssp0",
+               .clk            = &ref24_clk,
        }
 };
 
@@ -342,7 +370,7 @@ static int __init clk_init(void)
 
        return 0;
 }
-arch_initcall(clk_init);
+core_initcall(clk_init);
 
 /*
  * CLCD support.
index 2f5ccb298858def61458ed544fdac81383718982..002ab5d8c11c31705ce2f419b16a0fa9b23ccfa8 100644 (file)
@@ -26,6 +26,7 @@
 /*
  * Peripheral addresses
  */
+#define REALVIEW_PB1176_UART4_BASE             0x10009000 /* UART 4 */
 #define REALVIEW_PB1176_SCTL_BASE              0x10100000 /* System controller */
 #define REALVIEW_PB1176_SMC_BASE               0x10111000 /* SMC */
 #define REALVIEW_PB1176_DMC_BASE               0x10109000 /* DMC configuration */
index 830055bb86289860626fd5cbbfb08a3c64bfe04e..5c3c625e3e04f3b84db19f25a3c1c849f3833a5b 100644 (file)
@@ -40,6 +40,7 @@
 #define IRQ_DC1176_L2CC                (IRQ_DC1176_GIC_START + 13)
 #define IRQ_DC1176_RTC         (IRQ_DC1176_GIC_START + 14)
 #define IRQ_DC1176_CLCD                (IRQ_DC1176_GIC_START + 15)     /* CLCD controller */
+#define IRQ_DC1176_SSP         (IRQ_DC1176_GIC_START + 17)     /* SSP port */
 #define IRQ_DC1176_UART0       (IRQ_DC1176_GIC_START + 18)     /* UART 0 on development chip */
 #define IRQ_DC1176_UART1       (IRQ_DC1176_GIC_START + 19)     /* UART 1 on development chip */
 #define IRQ_DC1176_UART2       (IRQ_DC1176_GIC_START + 20)     /* UART 2 on development chip */
@@ -73,7 +74,6 @@
 #define IRQ_PB1176_RTC         (IRQ_PB1176_GIC_START + 25)     /* Real Time Clock */
 
 #define IRQ_PB1176_GPIO0       -1
-#define IRQ_PB1176_SSP         -1
 #define IRQ_PB1176_SCTL                -1
 
 #define NR_GIC_PB1176          2
index 2417bbcf97fd267ff236c09f31d71ef86ad2a047..5dafc157b276207f91837923cd2efd51762820cd 100644 (file)
 #endif
 
 #if !defined(__ASSEMBLY__) && defined(CONFIG_ZONE_DMA)
-extern void realview_adjust_zones(int node, unsigned long *size,
-                                 unsigned long *hole);
-#define arch_adjust_zones(node, size, hole) \
-       realview_adjust_zones(node, size, hole)
+extern void realview_adjust_zones(unsigned long *size, unsigned long *hole);
+#define arch_adjust_zones(size, hole) \
+       realview_adjust_zones(size, hole)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_256M - 1)
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_256M)
index 4425018fab828c864e662dfb4bfd5db369a76a15..991c1f8390e2a8eccfbbfae39ccab3768a7badbe 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
@@ -129,6 +130,12 @@ static struct pl061_platform_data gpio2_plat_data = {
        .irq_base       = -1,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+       .bus_id = 0,
+       .enable_dma = 0,
+       .num_chipselect = 1,
+};
+
 /*
  * RealView EB AMBA devices
  */
@@ -213,7 +220,7 @@ AMBA_DEVICE(sci0,  "dev:sci0",  SCI,      NULL);
 AMBA_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
 AMBA_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
 AMBA_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
-AMBA_DEVICE(ssp0,  "dev:ssp0",  EB_SSP,   NULL);
+AMBA_DEVICE(ssp0,  "dev:ssp0",  EB_SSP,   &ssp0_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
@@ -324,6 +331,26 @@ static struct platform_device pmu_device = {
        .resource               = pmu_resources,
 };
 
+static struct resource char_lcd_resources[] = {
+       {
+               .start = REALVIEW_CHAR_LCD_BASE,
+               .end   = (REALVIEW_CHAR_LCD_BASE + SZ_4K - 1),
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_EB_CHARLCD,
+               .end    = IRQ_EB_CHARLCD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device char_lcd_device = {
+       .name           =       "arm-charlcd",
+       .id             =       -1,
+       .num_resources  =       ARRAY_SIZE(char_lcd_resources),
+       .resource       =       char_lcd_resources,
+};
+
 static void __init gic_init_irq(void)
 {
        if (core_tile_eb11mp() || core_tile_a9mp()) {
@@ -442,6 +469,7 @@ static void __init realview_eb_init(void)
 
        realview_flash_register(&realview_eb_flash_resource, 1);
        platform_device_register(&realview_i2c_device);
+       platform_device_register(&char_lcd_device);
        eth_device_register();
        realview_usb_register(realview_eb_isp1761_resources);
 
index 099a1f125cf8f6c10b1720ccdcee7623ff5a73ad..d2be12eb829eb3b759be8a37bc8020df9f01d253 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
@@ -123,6 +124,12 @@ static struct pl061_platform_data gpio2_plat_data = {
        .irq_base       = -1,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+       .bus_id = 0,
+       .enable_dma = 0,
+       .num_chipselect = 1,
+};
+
 /*
  * RealView PB1176 AMBA devices
  */
@@ -144,8 +151,6 @@ static struct pl061_platform_data gpio2_plat_data = {
 #define MPMC_DMA       { 0, 0 }
 #define PB1176_CLCD_IRQ        { IRQ_DC1176_CLCD, NO_IRQ }
 #define PB1176_CLCD_DMA        { 0, 0 }
-#define DMAC_IRQ       { IRQ_PB1176_DMAC, NO_IRQ }
-#define DMAC_DMA       { 0, 0 }
 #define SCTL_IRQ       { NO_IRQ, NO_IRQ }
 #define SCTL_DMA       { 0, 0 }
 #define PB1176_WATCHDOG_IRQ    { IRQ_DC1176_WATCHDOG, NO_IRQ }
@@ -166,7 +171,9 @@ static struct pl061_platform_data gpio2_plat_data = {
 #define PB1176_UART2_DMA       { 11, 10 }
 #define PB1176_UART3_IRQ       { IRQ_DC1176_UART3, NO_IRQ }
 #define PB1176_UART3_DMA       { 0x86, 0x87 }
-#define PB1176_SSP_IRQ         { IRQ_PB1176_SSP, NO_IRQ }
+#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 */
@@ -174,7 +181,7 @@ AMBA_DEVICE(aaci,   "fpga:aaci",    AACI,           NULL);
 AMBA_DEVICE(mmc0,      "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
 AMBA_DEVICE(kmi0,      "fpga:kmi0",    KMI0,           NULL);
 AMBA_DEVICE(kmi1,      "fpga:kmi1",    KMI1,           NULL);
-AMBA_DEVICE(uart3,     "fpga:uart3",   PB1176_UART3,   NULL);
+AMBA_DEVICE(uart4,     "fpga:uart4",   PB1176_UART4,   NULL);
 
 /* DevChip Primecells */
 AMBA_DEVICE(smc,       "dev:smc",      PB1176_SMC,     NULL);
@@ -188,18 +195,16 @@ AMBA_DEVICE(sci0, "dev:sci0",     SCI,            NULL);
 AMBA_DEVICE(uart0,     "dev:uart0",    PB1176_UART0,   NULL);
 AMBA_DEVICE(uart1,     "dev:uart1",    PB1176_UART1,   NULL);
 AMBA_DEVICE(uart2,     "dev:uart2",    PB1176_UART2,   NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PB1176_SSP,     NULL);
-
-/* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,      "issp:clcd",    PB1176_CLCD,    &clcd_plat_data);
-//AMBA_DEVICE(dmac,    "issp:dmac",    PB1176_DMAC,    NULL);
+AMBA_DEVICE(uart3,     "dev:uart3",    PB1176_UART3,   NULL);
+AMBA_DEVICE(ssp0,      "dev:ssp0",     PB1176_SSP,     &ssp0_plat_data);
+AMBA_DEVICE(clcd,      "dev:clcd",     PB1176_CLCD,    &clcd_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
-//     &dmac_device,
        &uart0_device,
        &uart1_device,
        &uart2_device,
        &uart3_device,
+       &uart4_device,
        &smc_device,
        &clcd_device,
        &sctl_device,
@@ -276,6 +281,26 @@ static struct platform_device pmu_device = {
        .resource               = &pmu_resource,
 };
 
+static struct resource char_lcd_resources[] = {
+       {
+               .start = REALVIEW_CHAR_LCD_BASE,
+               .end   = (REALVIEW_CHAR_LCD_BASE + SZ_4K - 1),
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_PB1176_CHARLCD,
+               .end    = IRQ_PB1176_CHARLCD,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device char_lcd_device = {
+       .name           =       "arm-charlcd",
+       .id             =       -1,
+       .num_resources  =       ARRAY_SIZE(char_lcd_resources),
+       .resource       =       char_lcd_resources,
+};
+
 static void __init gic_init_irq(void)
 {
        /* ARM1176 DevChip GIC, primary */
@@ -338,6 +363,7 @@ static void __init realview_pb1176_init(void)
        platform_device_register(&realview_i2c_device);
        realview_usb_register(realview_pb1176_isp1761_resources);
        platform_device_register(&pmu_device);
+       platform_device_register(&char_lcd_device);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
index 0e07a5ccb75f56de33bec477f242d93d88bca448..d591bc00b86ec74147b0ff0b8c7bb85e99d52041 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
@@ -124,6 +125,12 @@ static struct pl061_platform_data gpio2_plat_data = {
        .irq_base       = -1,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+       .bus_id = 0,
+       .enable_dma = 0,
+       .num_chipselect = 1,
+};
+
 /*
  * RealView PB11MPCore AMBA devices
  */
@@ -190,7 +197,7 @@ AMBA_DEVICE(sci0,   "dev:sci0",     SCI,            NULL);
 AMBA_DEVICE(uart0,     "dev:uart0",    PB11MP_UART0,   NULL);
 AMBA_DEVICE(uart1,     "dev:uart1",    PB11MP_UART1,   NULL);
 AMBA_DEVICE(uart2,     "dev:uart2",    PB11MP_UART2,   NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PB11MP_SSP,     NULL);
+AMBA_DEVICE(ssp0,      "dev:ssp0",     PB11MP_SSP,     &ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
 AMBA_DEVICE(clcd,      "issp:clcd",    PB11MP_CLCD,    &clcd_plat_data);
index ac2f06f1ca500e9bd26603b21ba6c6badf046e11..6c37621217bc916fba02af26a8d3163c4b1d4aec 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
 #include <linux/io.h>
 
 #include <asm/irq.h>
@@ -114,6 +115,12 @@ static struct pl061_platform_data gpio2_plat_data = {
        .irq_base       = -1,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+       .bus_id = 0,
+       .enable_dma = 0,
+       .num_chipselect = 1,
+};
+
 /*
  * RealView PBA8Core AMBA devices
  */
@@ -180,7 +187,7 @@ AMBA_DEVICE(sci0,   "dev:sci0",     SCI,            NULL);
 AMBA_DEVICE(uart0,     "dev:uart0",    PBA8_UART0,     NULL);
 AMBA_DEVICE(uart1,     "dev:uart1",    PBA8_UART1,     NULL);
 AMBA_DEVICE(uart2,     "dev:uart2",    PBA8_UART2,     NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PBA8_SSP,       NULL);
+AMBA_DEVICE(ssp0,      "dev:ssp0",     PBA8_SSP,       &ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
 AMBA_DEVICE(clcd,      "issp:clcd",    PBA8_CLCD,      &clcd_plat_data);
index 08fd683adc4ced929eb255fd8da2e3b733850a87..9428eff0b116addda238d99d492cbe9d80c6b8a5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
 #include <linux/io.h>
 
 #include <asm/irq.h>
@@ -136,6 +137,12 @@ static struct pl061_platform_data gpio2_plat_data = {
        .irq_base       = -1,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+       .bus_id = 0,
+       .enable_dma = 0,
+       .num_chipselect = 1,
+};
+
 /*
  * RealView PBXCore AMBA devices
  */
@@ -202,7 +209,7 @@ AMBA_DEVICE(sci0,   "dev:sci0",     SCI,            NULL);
 AMBA_DEVICE(uart0,     "dev:uart0",    PBX_UART0,      NULL);
 AMBA_DEVICE(uart1,     "dev:uart1",    PBX_UART1,      NULL);
 AMBA_DEVICE(uart2,     "dev:uart2",    PBX_UART2,      NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PBX_SSP,        NULL);
+AMBA_DEVICE(ssp0,      "dev:ssp0",     PBX_SSP,        &ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
 AMBA_DEVICE(clcd,      "issp:clcd",    PBX_CLCD,       &clcd_plat_data);
index 779b45b3f80fdca1f6815782eef8b8dfa81b4841..3ba3bab139d0917ce45feaeb079573428f8a2af2 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/memblock.h>
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/sysdev.h>
@@ -304,6 +305,13 @@ static void __init h1940_map_io(void)
        s3c_pm_init();
 }
 
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init h1940_reserve(void)
+{
+       memblock_reserve(0x30003000, 0x1000);
+       memblock_reserve(0x30081000, 0x1000);
+}
+
 static void __init h1940_init_irq(void)
 {
        s3c24xx_init_irq();
@@ -346,6 +354,7 @@ MACHINE_START(H1940, "IPAQ-H1940")
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = h1940_map_io,
+       .reserve        = h1940_reserve,
        .init_irq       = h1940_init_irq,
        .init_machine   = h1940_init,
        .timer          = &s3c24xx_timer,
index ba93a356a83998a2b6e0ab2dfc83be7945321345..054c9f92232aa676dad11c0b86359ad21ef47fa6 100644 (file)
@@ -119,7 +119,6 @@ static void __init smdk2413_fixup(struct machine_desc *desc,
                mi->nr_banks=1;
                mi->bank[0].start = 0x30000000;
                mi->bank[0].size = SZ_64M;
-               mi->bank[0].node = 0;
        }
 }
 
index 3ca9265b699716f518d6d5b9e28f4e6f3c9e3d53..f291ac25d31252a8882bc632434a2c03f71e0361 100644 (file)
@@ -137,7 +137,6 @@ static void __init vstms_fixup(struct machine_desc *desc,
                mi->nr_banks=1;
                mi->bank[0].start = 0x30000000;
                mi->bank[0].size = SZ_64M;
-               mi->bank[0].node = 0;
        }
 }
 
index 8603b577a24b7673703db6992e2a4e3d7549e8c6..142d1f92117651e60fdad7e55fcc52997e430962 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/memblock.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/init.h>
@@ -570,12 +571,20 @@ static void __init rx1950_init_machine(void)
        platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
 }
 
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init rx1950_reserve(void)
+{
+       memblock_reserve(0x30003000, 0x1000);
+       memblock_reserve(0x30081000, 0x1000);
+}
+
 MACHINE_START(RX1950, "HP iPAQ RX1950")
     /* Maintainers: Vasily Khoruzhick */
     .phys_io = S3C2410_PA_UART,
        .io_pg_offst = (((u32) S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params = S3C2410_SDRAM_PA + 0x100,
        .map_io = rx1950_map_io,
+       .reserve        = rx1950_reserve,
        .init_irq = s3c24xx_init_irq,
        .init_machine = rx1950_init_machine,
        .timer = &s3c24xx_timer,
index d2946de3f3659d3e2588cc980a727973b9716062..6bb44f75a9ce65094a35c1bdad78775c1c655eee 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/memblock.h>
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/tty.h>
@@ -191,6 +192,13 @@ static void __init rx3715_map_io(void)
        s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
 }
 
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init rx3715_reserve(void)
+{
+       memblock_reserve(0x30003000, 0x1000);
+       memblock_reserve(0x30081000, 0x1000);
+}
+
 static void __init rx3715_init_irq(void)
 {
        s3c24xx_init_irq();
@@ -214,6 +222,7 @@ MACHINE_START(RX3715, "IPAQ-RX3715")
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = rx3715_map_io,
+       .reserve        = rx3715_reserve,
        .init_irq       = rx3715_init_irq,
        .init_machine   = rx3715_init_machine,
        .timer          = &s3c24xx_timer,
index ec03f187c52bcef3e1cf28145b373016b7e66e2d..b7a9a601c2d1e18a407c6110976812e35ebf93a3 100644 (file)
@@ -13,8 +13,7 @@ extern void __init sa1100_init_gpio(void);
 
 #define SET_BANK(__nr,__start,__size) \
        mi->bank[__nr].start = (__start), \
-       mi->bank[__nr].size = (__size), \
-       mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
+       mi->bank[__nr].size = (__size)
 
 extern void (*sa1100fb_backlight_power)(int on);
 extern void (*sa1100fb_lcd_power)(int on);
index d5277f9bee77d8dc7a98b2acb60d494e5fcc9df1..128a1dfa96b9b4ae9f64286f5b11df60c2297d79 100644 (file)
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_SA1111
-void sa1111_adjust_zones(int node, unsigned long *size, unsigned long *holes);
+void sa1111_adjust_zones(unsigned long *size, unsigned long *holes);
 
-#define arch_adjust_zones(node, size, holes) \
-       sa1111_adjust_zones(node, size, holes)
+#define arch_adjust_zones(size, holes) \
+       sa1111_adjust_zones(size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_1M - 1)
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_1M)
index 3053e5b7f1685290eccc1c44a9b011c030ffd741..d9c4812f1c316c69ab650a44cd513948410320ce 100644 (file)
@@ -19,9 +19,8 @@
 
 #ifndef __ASSEMBLY__
 
-static inline void __arch_adjust_zones(int node, unsigned long *zone_size, unsigned long *zhole_size) 
+static inline void __arch_adjust_zones(unsigned long *zone_size, unsigned long *zhole_size)
 {
-  if (node != 0) return;
   /* Only the first 4 MB (=1024 Pages) are usable for DMA */
   /* See dev / -> .properties in OpenFirmware. */
   zone_size[1] = zone_size[0] - 1024;
@@ -30,8 +29,8 @@ static inline void __arch_adjust_zones(int node, unsigned long *zone_size, unsig
   zhole_size[0] = 0;
 }
 
-#define arch_adjust_zones(node, size, holes) \
-       __arch_adjust_zones(node, size, holes)
+#define arch_adjust_zones(size, holes) \
+       __arch_adjust_zones(size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_4M - 1)
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_4M)
index f2b88c5fe142841e718928a0bd787dc6185032c3..4c704b4e8b340c9a6482e2c3ec87da15029c67a8 100644 (file)
@@ -70,6 +70,18 @@ endmenu
 
 menu "Timer and clock configuration"
 
+config SHMOBILE_TIMER_HZ
+       int "Kernel HZ (jiffies per second)"
+       range 32 1024
+       default "128"
+       help
+         Allows the configuration of the timer frequency. It is customary
+         to have the timer interrupt run at 1000 Hz or 100 Hz, but in the
+         case of low timer frequencies other values may be more suitable.
+         SH-Mobile systems using a 32768 Hz RCLK for clock events may want
+         to select a HZ value such as 128 that can evenly divide RCLK.
+         A HZ value that does not divide evenly may cause timer drift.
+
 config SH_TIMER_CMT
        bool "CMT timer driver"
        default y
index 5179b72e1ee3d04186f2cfba7d675778853735ae..132256bb8c817b1b5ab9aa08cd1af7875b22ca00 100644 (file)
@@ -2,7 +2,6 @@
 #define __ASM_MACH_IRQS_H
 
 #define NR_IRQS         512
-#define NR_IRQS_LEGACY  8
 
 #define evt2irq(evt)           (((evt) >> 5) - 16)
 #define irq2evt(irq)           (((irq) + 16) << 5)
index 39f6ccf22294d1e8a9c27f90a771a3c0090fa2d5..18febf92f20a10bfe38df87fc75d6c7f23dd9d83 100644 (file)
@@ -341,8 +341,11 @@ static struct clk gpio_clk = {
        .recalc = &follow_parent,
 };
 
+static struct clk dummy_apb_pclk;
+
 /* array of all spear 3xx clock lookups */
 static struct clk_lookup spear_clk_lookups[] = {
+       { .con_id = "apb_pclk", .clk = &dummy_apb_pclk},
        /* root clks */
        { .con_id = "osc_32k_clk",      .clk = &osc_32k_clk},
        { .con_id = "osc_24m_clk",      .clk = &osc_24m_clk},
index 13e27c769685018bb82b75b745ca45c56bf6d5d9..36ff056b73219f5b07339ab627558a64eb96adae 100644 (file)
@@ -428,8 +428,11 @@ static struct clk gpio2_clk = {
        .recalc = &follow_parent,
 };
 
+static struct clk dummy_apb_pclk;
+
 /* array of all spear 6xx clock lookups */
 static struct clk_lookup spear_clk_lookups[] = {
+       { .con_id = "apb_pclk", .clk = &dummy_apb_pclk},
        /* root clks */
        { .con_id = "osc_32k_clk",      .clk = &osc_32k_clk},
        { .con_id = "osc_30m_clk",      .clk = &osc_30m_clk},
index 5af71d5ba6656c648fc724a36b66e6d419389a1d..5d12d547789e3f17ee993c9df7d8e1056486045b 100644 (file)
@@ -1212,6 +1212,8 @@ static struct clk ppm_clk = {
 };
 #endif
 
+static struct clk dummy_apb_pclk;
+
 #define DEF_LOOKUP(devid, clkref)              \
        {                                       \
        .dev_id = devid,                        \
@@ -1223,6 +1225,10 @@ static struct clk ppm_clk = {
  * look up through clockdevice.
  */
 static struct clk_lookup lookups[] = {
+       {
+               .con_id = "apb_pclk",
+               .clk = &dummy_apb_pclk,
+       },
        /* Connected directly to the AMBA bus */
        DEF_LOOKUP("amba",      &amba_clk),
        DEF_LOOKUP("cpu",       &cpu_clk),
index ab000df7fc0337c7f75ef31deb9bef182ac172f0..bf134bcc129d612cde5362a6971a08360a42b582 100644 (file)
            (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024 + 0x100)
 #endif
 
-/*
- * TCM memory whereabouts
- */
-#define ITCM_OFFSET    0xffff2000
-#define ITCM_END       0xffff3fff
-#define DTCM_OFFSET    0xffff4000
-#define DTCM_END       0xffff5fff
-
 /*
  * We enable a real big DMA buffer if need be.
  */
index d2a0b8847a18061e36576f5dec89bc567745d473..bfcda9820888b6083fd10779b63fe89580f76036 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/memblock.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+static void __init u300_reserve(void)
+{
+       /*
+        * U300 - This platform family can share physical memory
+        * between two ARM cpus, one running Linux and the other
+        * running another OS.
+        */
+#ifdef CONFIG_MACH_U300_SINGLE_RAM
+#if ((CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1) == 1) && \
+       CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
+        memblock_reserve(PHYS_OFFSET, 0x00100000);
+#endif
+#endif
+}
+
 static void __init u300_init_machine(void)
 {
        u300_init_devices();
@@ -49,6 +65,7 @@ MACHINE_START(U300, MACH_U300_STRING)
        .io_pg_offst    = ((U300_AHB_PER_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = BOOT_PARAMS_OFFSET,
        .map_io         = u300_map_io,
+       .reserve        = u300_reserve,
        .init_irq       = u300_init_irq,
        .timer          = &u300_timer,
        .init_machine   = u300_init_machine,
index bb8d7b771817b774a7ff3406e87d46552cf8391c..0e8fd135a57dee1d56afb200208d62bf7d756fa8 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/pl022.h>
 #include <linux/spi/spi.h>
+#include <linux/mfd/ab8500.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include <plat/pincfg.h>
 #include <plat/i2c.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
 
+#include "pins-db8500.h"
+
+static pin_cfg_t mop500_pins[] = {
+       /* SSP0 */
+       GPIO143_SSP0_CLK,
+       GPIO144_SSP0_FRM,
+       GPIO145_SSP0_RXD,
+       GPIO146_SSP0_TXD,
+
+       /* I2C */
+       GPIO147_I2C0_SCL,
+       GPIO148_I2C0_SDA,
+       GPIO16_I2C1_SCL,
+       GPIO17_I2C1_SDA,
+       GPIO10_I2C2_SDA,
+       GPIO11_I2C2_SCL,
+       GPIO229_I2C3_SDA,
+       GPIO230_I2C3_SCL,
+};
+
 static void ab4500_spi_cs_control(u32 command)
 {
        /* set the FRM signal, which is CS  - TODO */
@@ -48,15 +71,20 @@ struct pl022_config_chip ab4500_chip_info = {
        .cs_control = ab4500_spi_cs_control,
 };
 
+static struct ab8500_platform_data ab8500_platdata = {
+       .irq_base       = MOP500_AB8500_IRQ_BASE,
+};
+
 static struct spi_board_info u8500_spi_devices[] = {
        {
                .modalias = "ab8500",
                .controller_data = &ab4500_chip_info,
+               .platform_data = &ab8500_platdata,
                .max_speed_hz = 12000000,
                .bus_num = 0,
                .chip_select = 0,
                .mode = SPI_MODE_0,
-               .irq = IRQ_AB4500,
+               .irq = IRQ_DB8500_AB8500,
        },
 };
 
@@ -118,6 +146,10 @@ static void __init u8500_init_machine(void)
 {
        int i;
 
+       u8500_init_devices();
+
+       nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins));
+
        u8500_i2c0_device.dev.platform_data = &u8500_i2c0_data;
        ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
        ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
@@ -133,8 +165,6 @@ static void __init u8500_init_machine(void)
 
        spi_register_board_info(u8500_spi_devices,
                        ARRAY_SIZE(u8500_spi_devices));
-
-       u8500_init_devices();
 }
 
 MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
index 0a1318fc8e2bd6c29774bcf1ab8cc48f6a5cfa0c..d8ab7f184fe439ec2492079a063def04c5e3c690 100644 (file)
@@ -453,7 +453,11 @@ static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
 static DEFINE_PRCC_CLK(7, wdg_ed,      1, -1, NULL);
 static DEFINE_PRCC_CLK(7, cfgreg_ed,   0, -1, NULL);
 
+static struct clk clk_dummy_apb_pclk;
+
 static struct clk_lookup u8500_common_clks[] = {
+       CLK(dummy_apb_pclk, NULL,       "apb_pclk"),
+
        /* Peripheral Cluster #1 */
        CLK(gpio0,      "gpio.0",       NULL),
        CLK(gpio0,      "gpio.1",       NULL),
index 8229034219432ad1f2090fe99b5da7723992ac22..654fca944e6554cd65eb77fff9c9563a96e58173 100644 (file)
@@ -65,7 +65,7 @@ struct amba_device u8500_ssp0_device = {
                .end   = U8500_SSP0_BASE + SZ_4K - 1,
                .flags = IORESOURCE_MEM,
        },
-       .irq = {IRQ_SSP0, NO_IRQ },
+       .irq = {IRQ_DB8500_SSP0, NO_IRQ },
        /* ST-Ericsson modified id */
        .periphid = SSP_PER_ID,
 };
@@ -77,8 +77,8 @@ static struct resource u8500_i2c0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_I2C0,
-               .end    = IRQ_I2C0,
+               .start  = IRQ_DB8500_I2C0,
+               .end    = IRQ_DB8500_I2C0,
                .flags  = IORESOURCE_IRQ,
        }
 };
@@ -97,8 +97,8 @@ static struct resource u8500_i2c4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_I2C4,
-               .end    = IRQ_I2C4,
+               .start  = IRQ_DB8500_I2C4,
+               .end    = IRQ_DB8500_I2C4,
                .flags  = IORESOURCE_IRQ,
        }
 };
@@ -130,8 +130,8 @@ static struct resource dma40_resources[] = {
                .name = "lcla",
        },
        [3] = {
-               .start = IRQ_DMA,
-               .end = IRQ_DMA,
+               .start = IRQ_DB8500_DMA,
+               .end   = IRQ_DB8500_DMA,
                .flags = IORESOURCE_IRQ}
 };
 
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
new file mode 100644 (file)
index 0000000..cca4f70
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_BOARD_MOP500_H
+#define __MACH_IRQS_BOARD_MOP500_H
+
+#define AB8500_NR_IRQS                 104
+
+#define MOP500_AB8500_IRQ_BASE         IRQ_BOARD_START
+#define MOP500_AB8500_IRQ_END          (MOP500_AB8500_IRQ_BASE \
+                                        + AB8500_NR_IRQS)
+#define MOP500_IRQ_END                 MOP500_AB8500_IRQ_END
+
+#if MOP500_IRQ_END > IRQ_BOARD_END
+#undef IRQ_BOARD_END
+#define IRQ_BOARD_END  MOP500_IRQ_END
+#endif
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
new file mode 100644 (file)
index 0000000..6fbfe5e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_DB5500_H
+#define __MACH_IRQS_DB5500_H
+
+#define IRQ_DB5500_MTU0                        (IRQ_SHPI_START + 4)
+#define IRQ_DB5500_SPI2                        (IRQ_SHPI_START + 6)
+#define IRQ_DB5500_PMU0                        (IRQ_SHPI_START + 7)
+#define IRQ_DB5500_SPI0                        (IRQ_SHPI_START + 8)
+#define IRQ_DB5500_RTT                 (IRQ_SHPI_START + 9)
+#define IRQ_DB5500_PKA                 (IRQ_SHPI_START + 10)
+#define IRQ_DB5500_UART0               (IRQ_SHPI_START + 11)
+#define IRQ_DB5500_I2C3                        (IRQ_SHPI_START + 12)
+#define IRQ_DB5500_L2CC                        (IRQ_SHPI_START + 13)
+#define IRQ_DB5500_MSP0                        (IRQ_SHPI_START + 14)
+#define IRQ_DB5500_CRYP1               (IRQ_SHPI_START + 15)
+#define IRQ_DB5500_PMU1                        (IRQ_SHPI_START + 16)
+#define IRQ_DB5500_MTU1                        (IRQ_SHPI_START + 17)
+#define IRQ_DB5500_RTC                 (IRQ_SHPI_START + 18)
+#define IRQ_DB5500_UART1               (IRQ_SHPI_START + 19)
+#define IRQ_DB5500_USB_WAKEUP          (IRQ_SHPI_START + 20)
+#define IRQ_DB5500_I2C0                        (IRQ_SHPI_START + 21)
+#define IRQ_DB5500_I2C1                        (IRQ_SHPI_START + 22)
+#define IRQ_DB5500_USBOTG              (IRQ_SHPI_START + 23)
+#define IRQ_DB5500_DMA_SECURE          (IRQ_SHPI_START + 24)
+#define IRQ_DB5500_DMA                 (IRQ_SHPI_START + 25)
+#define IRQ_DB5500_UART2               (IRQ_SHPI_START + 26)
+#define IRQ_DB5500_ICN_PMU1            (IRQ_SHPI_START + 27)
+#define IRQ_DB5500_ICN_PMU2            (IRQ_SHPI_START + 28)
+#define IRQ_DB5500_UART3               (IRQ_SHPI_START + 29)
+#define IRQ_DB5500_SPI3                        (IRQ_SHPI_START + 30)
+#define IRQ_DB5500_SDMMC4              (IRQ_SHPI_START + 31)
+#define IRQ_DB5500_IRRC                        (IRQ_SHPI_START + 33)
+#define IRQ_DB5500_IRDA_FT             (IRQ_SHPI_START + 34)
+#define IRQ_DB5500_IRDA_SD             (IRQ_SHPI_START + 35)
+#define IRQ_DB5500_IRDA_FI             (IRQ_SHPI_START + 36)
+#define IRQ_DB5500_IRDA_FD             (IRQ_SHPI_START + 37)
+#define IRQ_DB5500_FSMC_CODEREADY      (IRQ_SHPI_START + 38)
+#define IRQ_DB5500_FSMC_NANDWAIT       (IRQ_SHPI_START + 39)
+#define IRQ_DB5500_AB5500              (IRQ_SHPI_START + 40)
+#define IRQ_DB5500_SDMMC2              (IRQ_SHPI_START + 41)
+#define IRQ_DB5500_SIA                 (IRQ_SHPI_START + 42)
+#define IRQ_DB5500_SIA2                        (IRQ_SHPI_START + 43)
+#define IRQ_DB5500_HVA                 (IRQ_SHPI_START + 44)
+#define IRQ_DB5500_HVA2                        (IRQ_SHPI_START + 45)
+#define IRQ_DB5500_PRCMU0              (IRQ_SHPI_START + 46)
+#define IRQ_DB5500_PRCMU1              (IRQ_SHPI_START + 47)
+#define IRQ_DB5500_DISP                        (IRQ_SHPI_START + 48)
+#define IRQ_DB5500_SDMMC1              (IRQ_SHPI_START + 50)
+#define IRQ_DB5500_MSP1                        (IRQ_SHPI_START + 52)
+#define IRQ_DB5500_KBD                 (IRQ_SHPI_START + 53)
+#define IRQ_DB5500_I2C2                        (IRQ_SHPI_START + 55)
+#define IRQ_DB5500_B2R2                        (IRQ_SHPI_START + 56)
+#define IRQ_DB5500_CRYP0               (IRQ_SHPI_START + 57)
+#define IRQ_DB5500_SDMMC3              (IRQ_SHPI_START + 59)
+#define IRQ_DB5500_SDMMC0              (IRQ_SHPI_START + 60)
+#define IRQ_DB5500_HSEM                        (IRQ_SHPI_START + 61)
+#define IRQ_DB5500_SBAG                        (IRQ_SHPI_START + 63)
+#define IRQ_DB5500_SPI1                        (IRQ_SHPI_START + 96)
+#define IRQ_DB5500_MSP2                        (IRQ_SHPI_START + 98)
+#define IRQ_DB5500_SRPTIMER            (IRQ_SHPI_START + 101)
+#define IRQ_DB5500_CTI0                        (IRQ_SHPI_START + 108)
+#define IRQ_DB5500_CTI1                        (IRQ_SHPI_START + 109)
+#define IRQ_DB5500_ICN_ERR             (IRQ_SHPI_START + 110)
+#define IRQ_DB5500_MALI_PPMMU          (IRQ_SHPI_START + 112)
+#define IRQ_DB5500_MALI_PP             (IRQ_SHPI_START + 113)
+#define IRQ_DB5500_MALI_GPMMU          (IRQ_SHPI_START + 114)
+#define IRQ_DB5500_MALI_GP             (IRQ_SHPI_START + 115)
+#define IRQ_DB5500_MALI                        (IRQ_SHPI_START + 116)
+#define IRQ_DB5500_PRCMU_SEM           (IRQ_SHPI_START + 118)
+#define IRQ_DB5500_GPIO0               (IRQ_SHPI_START + 119)
+#define IRQ_DB5500_GPIO1               (IRQ_SHPI_START + 120)
+#define IRQ_DB5500_GPIO2               (IRQ_SHPI_START + 121)
+#define IRQ_DB5500_GPIO3               (IRQ_SHPI_START + 122)
+#define IRQ_DB5500_GPIO4               (IRQ_SHPI_START + 123)
+#define IRQ_DB5500_GPIO5               (IRQ_SHPI_START + 124)
+#define IRQ_DB5500_GPIO6               (IRQ_SHPI_START + 125)
+#define IRQ_DB5500_GPIO7               (IRQ_SHPI_START + 126)
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db8500.h b/arch/arm/mach-ux500/include/mach/irqs-db8500.h
new file mode 100644 (file)
index 0000000..8b5d9f0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_DB8500_H
+#define __MACH_IRQS_DB8500_H
+
+#define IRQ_DB8500_MTU0                        (IRQ_SHPI_START + 4)
+#define IRQ_DB8500_SPI2                        (IRQ_SHPI_START + 6)
+#define IRQ_DB8500_PMU                 (IRQ_SHPI_START + 7)
+#define IRQ_DB8500_SPI0                        (IRQ_SHPI_START + 8)
+#define IRQ_DB8500_RTT                 (IRQ_SHPI_START + 9)
+#define IRQ_DB8500_PKA                 (IRQ_SHPI_START + 10)
+#define IRQ_DB8500_UART0               (IRQ_SHPI_START + 11)
+#define IRQ_DB8500_I2C3                        (IRQ_SHPI_START + 12)
+#define IRQ_DB8500_L2CC                        (IRQ_SHPI_START + 13)
+#define IRQ_DB8500_SSP0                        (IRQ_SHPI_START + 14)
+#define IRQ_DB8500_CRYP1               (IRQ_SHPI_START + 15)
+#define IRQ_DB8500_MSP1_RX             (IRQ_SHPI_START + 16)
+#define IRQ_DB8500_MTU1                        (IRQ_SHPI_START + 17)
+#define IRQ_DB8500_RTC                 (IRQ_SHPI_START + 18)
+#define IRQ_DB8500_UART1               (IRQ_SHPI_START + 19)
+#define IRQ_DB8500_USB_WAKEUP          (IRQ_SHPI_START + 20)
+#define IRQ_DB8500_I2C0                        (IRQ_SHPI_START + 21)
+#define IRQ_DB8500_I2C1                        (IRQ_SHPI_START + 22)
+#define IRQ_DB8500_USBOTG              (IRQ_SHPI_START + 23)
+#define IRQ_DB8500_DMA_SECURE          (IRQ_SHPI_START + 24)
+#define IRQ_DB8500_DMA                 (IRQ_SHPI_START + 25)
+#define IRQ_DB8500_UART2               (IRQ_SHPI_START + 26)
+#define IRQ_DB8500_ICN_PMU1            (IRQ_SHPI_START + 27)
+#define IRQ_DB8500_ICN_PMU2            (IRQ_SHPI_START + 28)
+#define IRQ_DB8500_HSIR_EXCEP          (IRQ_SHPI_START + 29)
+#define IRQ_DB8500_MSP0                        (IRQ_SHPI_START + 31)
+#define IRQ_DB8500_HSIR_CH0_OVRRUN     (IRQ_SHPI_START + 32)
+#define IRQ_DB8500_HSIR_CH1_OVRRUN     (IRQ_SHPI_START + 33)
+#define IRQ_DB8500_HSIR_CH2_OVRRUN     (IRQ_SHPI_START + 34)
+#define IRQ_DB8500_HSIR_CH3_OVRRUN     (IRQ_SHPI_START + 35)
+#define IRQ_DB8500_HSIR_CH4_OVRRUN     (IRQ_SHPI_START + 36)
+#define IRQ_DB8500_HSIR_CH5_OVRRUN     (IRQ_SHPI_START + 37)
+#define IRQ_DB8500_HSIR_CH6_OVRRUN     (IRQ_SHPI_START + 38)
+#define IRQ_DB8500_HSIR_CH7_OVRRUN     (IRQ_SHPI_START + 39)
+#define IRQ_DB8500_AB8500              (IRQ_SHPI_START + 40)
+#define IRQ_DB8500_SDMMC2              (IRQ_SHPI_START + 41)
+#define IRQ_DB8500_SIA                 (IRQ_SHPI_START + 42)
+#define IRQ_DB8500_SIA2                        (IRQ_SHPI_START + 43)
+#define IRQ_DB8500_SVA                 (IRQ_SHPI_START + 44)
+#define IRQ_DB8500_SVA2                        (IRQ_SHPI_START + 45)
+#define IRQ_DB8500_PRCMU0              (IRQ_SHPI_START + 46)
+#define IRQ_DB8500_PRCMU1              (IRQ_SHPI_START + 47)
+#define IRQ_DB8500_DISP                        (IRQ_SHPI_START + 48)
+#define IRQ_DB8500_SPI3                        (IRQ_SHPI_START + 49)
+#define IRQ_DB8500_SDMMC1              (IRQ_SHPI_START + 50)
+#define IRQ_DB8500_I2C4                        (IRQ_SHPI_START + 51)
+#define IRQ_DB8500_SSP1                        (IRQ_SHPI_START + 52)
+#define IRQ_DB8500_SKE                 (IRQ_SHPI_START + 53)
+#define IRQ_DB8500_KB                  (IRQ_SHPI_START + 54)
+#define IRQ_DB8500_I2C2                        (IRQ_SHPI_START + 55)
+#define IRQ_DB8500_B2R2                        (IRQ_SHPI_START + 56)
+#define IRQ_DB8500_CRYP0               (IRQ_SHPI_START + 57)
+#define IRQ_DB8500_SDMMC3              (IRQ_SHPI_START + 59)
+#define IRQ_DB8500_SDMMC0              (IRQ_SHPI_START + 60)
+#define IRQ_DB8500_HSEM                        (IRQ_SHPI_START + 61)
+#define IRQ_DB8500_MSP1                        (IRQ_SHPI_START + 62)
+#define IRQ_DB8500_SBAG                        (IRQ_SHPI_START + 63)
+#define IRQ_DB8500_SPI1                        (IRQ_SHPI_START + 96)
+#define IRQ_DB8500_SRPTIMER            (IRQ_SHPI_START + 97)
+#define IRQ_DB8500_MSP2                        (IRQ_SHPI_START + 98)
+#define IRQ_DB8500_SDMMC4              (IRQ_SHPI_START + 99)
+#define IRQ_DB8500_SDMMC5              (IRQ_SHPI_START + 100)
+#define IRQ_DB8500_HSIRD0              (IRQ_SHPI_START + 104)
+#define IRQ_DB8500_HSIRD1              (IRQ_SHPI_START + 105)
+#define IRQ_DB8500_HSITD0              (IRQ_SHPI_START + 106)
+#define IRQ_DB8500_HSITD1              (IRQ_SHPI_START + 107)
+#define IRQ_DB8500_CTI0                        (IRQ_SHPI_START + 108)
+#define IRQ_DB8500_CTI1                        (IRQ_SHPI_START + 109)
+#define IRQ_DB8500_ICN_ERR             (IRQ_SHPI_START + 110)
+#define IRQ_DB8500_MALI_PPMMU          (IRQ_SHPI_START + 112)
+#define IRQ_DB8500_MALI_PP             (IRQ_SHPI_START + 113)
+#define IRQ_DB8500_MALI_GPMMU          (IRQ_SHPI_START + 114)
+#define IRQ_DB8500_MALI_GP             (IRQ_SHPI_START + 115)
+#define IRQ_DB8500_MALI                        (IRQ_SHPI_START + 116)
+#define IRQ_DB8500_PRCMU_SEM           (IRQ_SHPI_START + 118)
+#define IRQ_DB8500_GPIO0               (IRQ_SHPI_START + 119)
+#define IRQ_DB8500_GPIO1               (IRQ_SHPI_START + 120)
+#define IRQ_DB8500_GPIO2               (IRQ_SHPI_START + 121)
+#define IRQ_DB8500_GPIO3               (IRQ_SHPI_START + 122)
+#define IRQ_DB8500_GPIO4               (IRQ_SHPI_START + 123)
+#define IRQ_DB8500_GPIO5               (IRQ_SHPI_START + 124)
+#define IRQ_DB8500_GPIO6               (IRQ_SHPI_START + 125)
+#define IRQ_DB8500_GPIO7               (IRQ_SHPI_START + 126)
+#define IRQ_DB8500_GPIO8               (IRQ_SHPI_START + 127)
+
+#endif
index 7970684b1d0983841bd74e623daf93412fd8797e..10385bdc2b7760506af333077fd1fd34fe5972fc 100644 (file)
@@ -10,7 +10,8 @@
 #ifndef ASM_ARCH_IRQS_H
 #define ASM_ARCH_IRQS_H
 
-#include <mach/hardware.h>
+#include <mach/irqs-db5500.h>
+#include <mach/irqs-db8500.h>
 
 #define IRQ_LOCALTIMER                  29
 #define IRQ_LOCALWDOG                   30
 /* There are 128 shared peripheral interrupts assigned to
  * INTID[160:32]. The first 32 interrupts are reserved.
  */
-#define U8500_SOC_NR_IRQS              161
+#define DBX500_NR_INTERNAL_IRQS                161
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO                        288
-#define NOMADIK_GPIO_TO_IRQ(gpio)      ((gpio) + U8500_SOC_NR_IRQS)
-#define NOMADIK_IRQ_TO_GPIO(irq)       ((irq) - U8500_SOC_NR_IRQS)
-#define NR_IRQS                                NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+#define NOMADIK_GPIO_TO_IRQ(gpio)      ((gpio) + DBX500_NR_INTERNAL_IRQS)
+#define NOMADIK_IRQ_TO_GPIO(irq)       ((irq) - DBX500_NR_INTERNAL_IRQS)
+#define IRQ_BOARD_START                        NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
 
-#endif /*ASM_ARCH_IRQS_H*/
+/* This will be overridden by board-specific irq headers */
+#define IRQ_BOARD_END                  IRQ_BOARD_START
+
+#ifdef CONFIG_MACH_U8500_MOP
+#include <mach/irqs-board-mop500.h>
+#endif
+
+#define NR_IRQS                                IRQ_BOARD_END
+
+#endif /* ASM_ARCH_IRQS_H */
index 8552eb188b50274c7ed4b18ccf48e743192652de..0271ca0a83df86c4fb43eb37b3c93754414d706d 100644 (file)
 static void putc(const char c)
 {
        /* Do nothing if the UART is not enabled. */
-       if (!(readb(U8500_UART_CR) & 0x1))
+       if (!(__raw_readb(U8500_UART_CR) & 0x1))
                return;
 
        if (c == '\n')
                putc('\r');
 
-       while (readb(U8500_UART_FR) & (1 << 5))
+       while (__raw_readb(U8500_UART_FR) & (1 << 5))
                barrier();
-       writeb(c, U8500_UART_DR);
+       __raw_writeb(c, U8500_UART_DR);
 }
 
 static void flush(void)
 {
-       if (!(readb(U8500_UART_CR) & 0x1))
+       if (!(__raw_readb(U8500_UART_CR) & 0x1))
                return;
-       while (readb(U8500_UART_FR) & (1 << 3))
+       while (__raw_readb(U8500_UART_FR) & (1 << 3))
                barrier();
 }
 
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
new file mode 100644 (file)
index 0000000..9055d5d
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ */
+
+#ifndef __MACH_PINS_DB8500_H
+#define __MACH_PINS_DB8500_H
+
+/*
+ * TODO: Eventually encode all non-board specific pull up/down configuration
+ * here.
+ */
+
+#define GPIO0_GPIO             PIN_CFG(0, GPIO)
+#define GPIO0_U0_CTSn          PIN_CFG(0, ALT_A)
+#define GPIO0_TRIG_OUT         PIN_CFG(0, ALT_B)
+#define GPIO0_IP_TDO           PIN_CFG(0, ALT_C)
+
+#define GPIO1_GPIO             PIN_CFG(1, GPIO)
+#define GPIO1_U0_RTSn          PIN_CFG(1, ALT_A)
+#define GPIO1_TRIG_IN          PIN_CFG(1, ALT_B)
+#define GPIO1_IP_TDI           PIN_CFG(1, ALT_C)
+
+#define GPIO2_GPIO             PIN_CFG(2, GPIO)
+#define GPIO2_U0_RXD           PIN_CFG(2, ALT_A)
+#define GPIO2_NONE             PIN_CFG(2, ALT_B)
+#define GPIO2_IP_TMS           PIN_CFG(2, ALT_C)
+
+#define GPIO3_GPIO             PIN_CFG(3, GPIO)
+#define GPIO3_U0_TXD           PIN_CFG(3, ALT_A)
+#define GPIO3_NONE             PIN_CFG(3, ALT_B)
+#define GPIO3_IP_TCK           PIN_CFG(3, ALT_C)
+
+#define GPIO4_GPIO             PIN_CFG(4, GPIO)
+#define GPIO4_U1_RXD           PIN_CFG(4, ALT_A)
+#define GPIO4_I2C4_SCL         PIN_CFG_PULL(4, ALT_B, UP)
+#define GPIO4_IP_TRSTn         PIN_CFG(4, ALT_C)
+
+#define GPIO5_GPIO             PIN_CFG(5, GPIO)
+#define GPIO5_U1_TXD           PIN_CFG(5, ALT_A)
+#define GPIO5_I2C4_SDA         PIN_CFG_PULL(5, ALT_B, UP)
+#define GPIO5_IP_GPIO6         PIN_CFG(5, ALT_C)
+
+#define GPIO6_GPIO             PIN_CFG(6, GPIO)
+#define GPIO6_U1_CTSn          PIN_CFG(6, ALT_A)
+#define GPIO6_I2C1_SCL         PIN_CFG_PULL(6, ALT_B, UP)
+#define GPIO6_IP_GPIO0         PIN_CFG(6, ALT_C)
+
+#define GPIO7_GPIO             PIN_CFG(7, GPIO)
+#define GPIO7_U1_RTSn          PIN_CFG(7, ALT_A)
+#define GPIO7_I2C1_SDA         PIN_CFG_PULL(7, ALT_B, UP)
+#define GPIO7_IP_GPIO1         PIN_CFG(7, ALT_C)
+
+#define GPIO8_GPIO             PIN_CFG(8, GPIO)
+#define GPIO8_IPI2C_SDA                PIN_CFG_PULL(8, ALT_A, UP)
+#define GPIO8_I2C2_SDA         PIN_CFG_PULL(8, ALT_B, UP)
+
+#define GPIO9_GPIO             PIN_CFG(9, GPIO)
+#define GPIO9_IPI2C_SCL                PIN_CFG_PULL(9, ALT_A, UP)
+#define GPIO9_I2C2_SCL         PIN_CFG_PULL(9, ALT_B, UP)
+
+#define GPIO10_GPIO            PIN_CFG(10, GPIO)
+#define GPIO10_IPI2C_SDA       PIN_CFG_PULL(10, ALT_A, UP)
+#define GPIO10_I2C2_SDA                PIN_CFG_PULL(10, ALT_B, UP)
+#define GPIO10_IP_GPIO3                PIN_CFG(10, ALT_C)
+
+#define GPIO11_GPIO            PIN_CFG(11, GPIO)
+#define GPIO11_IPI2C_SCL       PIN_CFG_PULL(11, ALT_A, UP)
+#define GPIO11_I2C2_SCL                PIN_CFG_PULL(11, ALT_B, UP)
+#define GPIO11_IP_GPIO2                PIN_CFG(11, ALT_C)
+
+#define GPIO12_GPIO            PIN_CFG(12, GPIO)
+#define GPIO12_MSP0_TXD                PIN_CFG(12, ALT_A)
+#define GPIO12_MSP0_RXD                PIN_CFG(12, ALT_B)
+
+#define GPIO13_GPIO            PIN_CFG(13, GPIO)
+#define GPIO13_MSP0_TFS                PIN_CFG(13, ALT_A)
+
+#define GPIO14_GPIO            PIN_CFG(14, GPIO)
+#define GPIO14_MSP0_TCK                PIN_CFG(14, ALT_A)
+
+#define GPIO15_GPIO            PIN_CFG(15, GPIO)
+#define GPIO15_MSP0_RXD                PIN_CFG(15, ALT_A)
+#define GPIO15_MSP0_TXD                PIN_CFG(15, ALT_B)
+
+#define GPIO16_GPIO            PIN_CFG(16, GPIO)
+#define GPIO16_MSP0_RFS                PIN_CFG(16, ALT_A)
+#define GPIO16_I2C1_SCL                PIN_CFG_PULL(16, ALT_B, UP)
+#define GPIO16_SLIM0_DAT       PIN_CFG(16, ALT_C)
+
+#define GPIO17_GPIO            PIN_CFG(17, GPIO)
+#define GPIO17_MSP0_RCK                PIN_CFG(17, ALT_A)
+#define GPIO17_I2C1_SDA                PIN_CFG_PULL(17, ALT_B, UP)
+#define GPIO17_SLIM0_CLK       PIN_CFG(17, ALT_C)
+
+#define GPIO18_GPIO            PIN_CFG(18, GPIO)
+#define GPIO18_MC0_CMDDIR      PIN_CFG(18, ALT_A)
+#define GPIO18_U2_RXD          PIN_CFG(18, ALT_B)
+#define GPIO18_MS_IEP          PIN_CFG(18, ALT_C)
+
+#define GPIO19_GPIO            PIN_CFG(19, GPIO)
+#define GPIO19_MC0_DAT0DIR     PIN_CFG(19, ALT_A)
+#define GPIO19_U2_TXD          PIN_CFG(19, ALT_B)
+#define GPIO19_MS_DAT0DIR      PIN_CFG(19, ALT_C)
+
+#define GPIO20_GPIO            PIN_CFG(20, GPIO)
+#define GPIO20_MC0_DAT2DIR     PIN_CFG(20, ALT_A)
+#define GPIO20_UARTMOD_TXD     PIN_CFG(20, ALT_B)
+#define GPIO20_IP_TRIGOUT      PIN_CFG(20, ALT_C)
+
+#define GPIO21_GPIO            PIN_CFG(21, GPIO)
+#define GPIO21_MC0_DAT31DIR    PIN_CFG(21, ALT_A)
+#define GPIO21_MSP0_SCK                PIN_CFG(21, ALT_B)
+#define GPIO21_MS_DAT31DIR     PIN_CFG(21, ALT_C)
+
+#define GPIO22_GPIO            PIN_CFG(22, GPIO)
+#define GPIO22_MC0_FBCLK       PIN_CFG(22, ALT_A)
+#define GPIO22_UARTMOD_RXD     PIN_CFG(22, ALT_B)
+#define GPIO22_MS_FBCLK                PIN_CFG(22, ALT_C)
+
+#define GPIO23_GPIO            PIN_CFG(23, GPIO)
+#define GPIO23_MC0_CLK         PIN_CFG(23, ALT_A)
+#define GPIO23_STMMOD_CLK      PIN_CFG(23, ALT_B)
+#define GPIO23_MS_CLK          PIN_CFG(23, ALT_C)
+
+#define GPIO24_GPIO            PIN_CFG(24, GPIO)
+#define GPIO24_MC0_CMD         PIN_CFG(24, ALT_A)
+#define GPIO24_UARTMOD_RXD     PIN_CFG(24, ALT_B)
+#define GPIO24_MS_BS           PIN_CFG(24, ALT_C)
+
+#define GPIO25_GPIO            PIN_CFG(25, GPIO)
+#define GPIO25_MC0_DAT0                PIN_CFG(25, ALT_A)
+#define GPIO25_STMMOD_DAT0     PIN_CFG(25, ALT_B)
+#define GPIO25_MS_DAT0         PIN_CFG(25, ALT_C)
+
+#define GPIO26_GPIO            PIN_CFG(26, GPIO)
+#define GPIO26_MC0_DAT1                PIN_CFG(26, ALT_A)
+#define GPIO26_STMMOD_DAT1     PIN_CFG(26, ALT_B)
+#define GPIO26_MS_DAT1         PIN_CFG(26, ALT_C)
+
+#define GPIO27_GPIO            PIN_CFG(27, GPIO)
+#define GPIO27_MC0_DAT2                PIN_CFG(27, ALT_A)
+#define GPIO27_STMMOD_DAT2     PIN_CFG(27, ALT_B)
+#define GPIO27_MS_DAT2         PIN_CFG(27, ALT_C)
+
+#define GPIO28_GPIO            PIN_CFG(28, GPIO)
+#define GPIO28_MC0_DAT3                PIN_CFG(28, ALT_A)
+#define GPIO28_STMMOD_DAT3     PIN_CFG(28, ALT_B)
+#define GPIO28_MS_DAT3         PIN_CFG(28, ALT_C)
+
+#define GPIO29_GPIO            PIN_CFG(29, GPIO)
+#define GPIO29_MC0_DAT4                PIN_CFG(29, ALT_A)
+#define GPIO29_SPI3_CLK                PIN_CFG(29, ALT_B)
+#define GPIO29_U2_RXD          PIN_CFG(29, ALT_C)
+
+#define GPIO30_GPIO            PIN_CFG(30, GPIO)
+#define GPIO30_MC0_DAT5                PIN_CFG(30, ALT_A)
+#define GPIO30_SPI3_RXD                PIN_CFG(30, ALT_B)
+#define GPIO30_U2_TXD          PIN_CFG(30, ALT_C)
+
+#define GPIO31_GPIO            PIN_CFG(31, GPIO)
+#define GPIO31_MC0_DAT6                PIN_CFG(31, ALT_A)
+#define GPIO31_SPI3_FRM                PIN_CFG(31, ALT_B)
+#define GPIO31_U2_CTSn         PIN_CFG(31, ALT_C)
+
+#define GPIO32_GPIO            PIN_CFG(32, GPIO)
+#define GPIO32_MC0_DAT7                PIN_CFG(32, ALT_A)
+#define GPIO32_SPI3_TXD                PIN_CFG(32, ALT_B)
+#define GPIO32_U2_RTSn         PIN_CFG(32, ALT_C)
+
+#define GPIO33_GPIO            PIN_CFG(33, GPIO)
+#define GPIO33_MSP1_TXD                PIN_CFG(33, ALT_A)
+#define GPIO33_MSP1_RXD                PIN_CFG(33, ALT_B)
+#define GPIO33_U0_DTRn         PIN_CFG(33, ALT_C)
+
+#define GPIO34_GPIO            PIN_CFG(34, GPIO)
+#define GPIO34_MSP1_TFS                PIN_CFG(34, ALT_A)
+#define GPIO34_NONE            PIN_CFG(34, ALT_B)
+#define GPIO34_U0_DCDn         PIN_CFG(34, ALT_C)
+
+#define GPIO35_GPIO            PIN_CFG(35, GPIO)
+#define GPIO35_MSP1_TCK                PIN_CFG(35, ALT_A)
+#define GPIO35_NONE            PIN_CFG(35, ALT_B)
+#define GPIO35_U0_DSRn         PIN_CFG(35, ALT_C)
+
+#define GPIO36_GPIO            PIN_CFG(36, GPIO)
+#define GPIO36_MSP1_RXD                PIN_CFG(36, ALT_A)
+#define GPIO36_MSP1_TXD                PIN_CFG(36, ALT_B)
+#define GPIO36_U0_RIn          PIN_CFG(36, ALT_C)
+
+#define GPIO64_GPIO            PIN_CFG(64, GPIO)
+#define GPIO64_LCDB_DE         PIN_CFG(64, ALT_A)
+#define GPIO64_KP_O1           PIN_CFG(64, ALT_B)
+#define GPIO64_IP_GPIO4                PIN_CFG(64, ALT_C)
+
+#define GPIO65_GPIO            PIN_CFG(65, GPIO)
+#define GPIO65_LCDB_HSO                PIN_CFG(65, ALT_A)
+#define GPIO65_KP_O0           PIN_CFG(65, ALT_B)
+#define GPIO65_IP_GPIO5                PIN_CFG(65, ALT_C)
+
+#define GPIO66_GPIO            PIN_CFG(66, GPIO)
+#define GPIO66_LCDB_VSO                PIN_CFG(66, ALT_A)
+#define GPIO66_KP_I1           PIN_CFG(66, ALT_B)
+#define GPIO66_IP_GPIO6                PIN_CFG(66, ALT_C)
+
+#define GPIO67_GPIO            PIN_CFG(67, GPIO)
+#define GPIO67_LCDB_CLK                PIN_CFG(67, ALT_A)
+#define GPIO67_KP_I0           PIN_CFG(67, ALT_B)
+#define GPIO67_IP_GPIO7                PIN_CFG(67, ALT_C)
+
+#define GPIO68_GPIO            PIN_CFG(68, GPIO)
+#define GPIO68_LCD_VSI0                PIN_CFG(68, ALT_A)
+#define GPIO68_KP_O7           PIN_CFG(68, ALT_B)
+#define GPIO68_SM_CLE          PIN_CFG(68, ALT_C)
+
+#define GPIO69_GPIO            PIN_CFG(69, GPIO)
+#define GPIO69_LCD_VSI1                PIN_CFG(69, ALT_A)
+#define GPIO69_KP_I7           PIN_CFG(69, ALT_B)
+#define GPIO69_SM_ALE          PIN_CFG(69, ALT_C)
+
+#define GPIO70_GPIO            PIN_CFG(70, GPIO)
+#define GPIO70_LCD_D0          PIN_CFG(70, ALT_A)
+#define GPIO70_KP_O5           PIN_CFG(70, ALT_B)
+#define GPIO70_STMAPE_CLK      PIN_CFG(70, ALT_C)
+
+#define GPIO71_GPIO            PIN_CFG(71, GPIO)
+#define GPIO71_LCD_D1          PIN_CFG(71, ALT_A)
+#define GPIO71_KP_O4           PIN_CFG(71, ALT_B)
+#define GPIO71_STMAPE_DAT3     PIN_CFG(71, ALT_C)
+
+#define GPIO72_GPIO            PIN_CFG(72, GPIO)
+#define GPIO72_LCD_D2          PIN_CFG(72, ALT_A)
+#define GPIO72_KP_O3           PIN_CFG(72, ALT_B)
+#define GPIO72_STMAPE_DAT2     PIN_CFG(72, ALT_C)
+
+#define GPIO73_GPIO            PIN_CFG(73, GPIO)
+#define GPIO73_LCD_D3          PIN_CFG(73, ALT_A)
+#define GPIO73_KP_O2           PIN_CFG(73, ALT_B)
+#define GPIO73_STMAPE_DAT1     PIN_CFG(73, ALT_C)
+
+#define GPIO74_GPIO            PIN_CFG(74, GPIO)
+#define GPIO74_LCD_D4          PIN_CFG(74, ALT_A)
+#define GPIO74_KP_I5           PIN_CFG(74, ALT_B)
+#define GPIO74_STMAPE_DAT0     PIN_CFG(74, ALT_C)
+
+#define GPIO75_GPIO            PIN_CFG(75, GPIO)
+#define GPIO75_LCD_D5          PIN_CFG(75, ALT_A)
+#define GPIO75_KP_I4           PIN_CFG(75, ALT_B)
+#define GPIO75_U2_RXD          PIN_CFG(75, ALT_C)
+
+#define GPIO76_GPIO            PIN_CFG(76, GPIO)
+#define GPIO76_LCD_D6          PIN_CFG(76, ALT_A)
+#define GPIO76_KP_I3           PIN_CFG(76, ALT_B)
+#define GPIO76_U2_TXD          PIN_CFG(76, ALT_C)
+
+#define GPIO77_GPIO            PIN_CFG(77, GPIO)
+#define GPIO77_LCD_D7          PIN_CFG(77, ALT_A)
+#define GPIO77_KP_I2           PIN_CFG(77, ALT_B)
+#define GPIO77_NONE            PIN_CFG(77, ALT_C)
+
+#define GPIO78_GPIO            PIN_CFG(78, GPIO)
+#define GPIO78_LCD_D8          PIN_CFG(78, ALT_A)
+#define GPIO78_KP_O6           PIN_CFG(78, ALT_B)
+#define GPIO78_IP_GPIO2                PIN_CFG(78, ALT_C)
+
+#define GPIO79_GPIO            PIN_CFG(79, GPIO)
+#define GPIO79_LCD_D9          PIN_CFG(79, ALT_A)
+#define GPIO79_KP_I6           PIN_CFG(79, ALT_B)
+#define GPIO79_IP_GPIO3                PIN_CFG(79, ALT_C)
+
+#define GPIO80_GPIO            PIN_CFG(80, GPIO)
+#define GPIO80_LCD_D10         PIN_CFG(80, ALT_A)
+#define GPIO80_KP_SKA0         PIN_CFG(80, ALT_B)
+#define GPIO80_IP_GPIO4                PIN_CFG(80, ALT_C)
+
+#define GPIO81_GPIO            PIN_CFG(81, GPIO)
+#define GPIO81_LCD_D11         PIN_CFG(81, ALT_A)
+#define GPIO81_KP_SKB0         PIN_CFG(81, ALT_B)
+#define GPIO81_IP_GPIO5                PIN_CFG(81, ALT_C)
+
+#define GPIO82_GPIO            PIN_CFG(82, GPIO)
+#define GPIO82_LCD_D12         PIN_CFG(82, ALT_A)
+#define GPIO82_KP_O5           PIN_CFG(82, ALT_B)
+
+#define GPIO83_GPIO            PIN_CFG(83, GPIO)
+#define GPIO83_LCD_D13         PIN_CFG(83, ALT_A)
+#define GPIO83_KP_O4           PIN_CFG(83, ALT_B)
+
+#define GPIO84_GPIO            PIN_CFG(84, GPIO)
+#define GPIO84_LCD_D14         PIN_CFG(84, ALT_A)
+#define GPIO84_KP_I5           PIN_CFG(84, ALT_B)
+
+#define GPIO85_GPIO            PIN_CFG(85, GPIO)
+#define GPIO85_LCD_D15         PIN_CFG(85, ALT_A)
+#define GPIO85_KP_I4           PIN_CFG(85, ALT_B)
+
+#define GPIO86_GPIO            PIN_CFG(86, GPIO)
+#define GPIO86_LCD_D16         PIN_CFG(86, ALT_A)
+#define GPIO86_SM_ADQ0         PIN_CFG(86, ALT_B)
+#define GPIO86_MC5_DAT0                PIN_CFG(86, ALT_C)
+
+#define GPIO87_GPIO            PIN_CFG(87, GPIO)
+#define GPIO87_LCD_D17         PIN_CFG(87, ALT_A)
+#define GPIO87_SM_ADQ1         PIN_CFG(87, ALT_B)
+#define GPIO87_MC5_DAT1                PIN_CFG(87, ALT_C)
+
+#define GPIO88_GPIO            PIN_CFG(88, GPIO)
+#define GPIO88_LCD_D18         PIN_CFG(88, ALT_A)
+#define GPIO88_SM_ADQ2         PIN_CFG(88, ALT_B)
+#define GPIO88_MC5_DAT2                PIN_CFG(88, ALT_C)
+
+#define GPIO89_GPIO            PIN_CFG(89, GPIO)
+#define GPIO89_LCD_D19         PIN_CFG(89, ALT_A)
+#define GPIO89_SM_ADQ3         PIN_CFG(89, ALT_B)
+#define GPIO89_MC5_DAT3                PIN_CFG(89, ALT_C)
+
+#define GPIO90_GPIO            PIN_CFG(90, GPIO)
+#define GPIO90_LCD_D20         PIN_CFG(90, ALT_A)
+#define GPIO90_SM_ADQ4         PIN_CFG(90, ALT_B)
+#define GPIO90_MC5_CMD         PIN_CFG(90, ALT_C)
+
+#define GPIO91_GPIO            PIN_CFG(91, GPIO)
+#define GPIO91_LCD_D21         PIN_CFG(91, ALT_A)
+#define GPIO91_SM_ADQ5         PIN_CFG(91, ALT_B)
+#define GPIO91_MC5_FBCLK       PIN_CFG(91, ALT_C)
+
+#define GPIO92_GPIO            PIN_CFG(92, GPIO)
+#define GPIO92_LCD_D22         PIN_CFG(92, ALT_A)
+#define GPIO92_SM_ADQ6         PIN_CFG(92, ALT_B)
+#define GPIO92_MC5_CLK         PIN_CFG(92, ALT_C)
+
+#define GPIO93_GPIO            PIN_CFG(93, GPIO)
+#define GPIO93_LCD_D23         PIN_CFG(93, ALT_A)
+#define GPIO93_SM_ADQ7         PIN_CFG(93, ALT_B)
+#define GPIO93_MC5_DAT4                PIN_CFG(93, ALT_C)
+
+#define GPIO94_GPIO            PIN_CFG(94, GPIO)
+#define GPIO94_KP_O7           PIN_CFG(94, ALT_A)
+#define GPIO94_SM_ADVn         PIN_CFG(94, ALT_B)
+#define GPIO94_MC5_DAT5                PIN_CFG(94, ALT_C)
+
+#define GPIO95_GPIO            PIN_CFG(95, GPIO)
+#define GPIO95_KP_I7           PIN_CFG(95, ALT_A)
+#define GPIO95_SM_CS0n         PIN_CFG(95, ALT_B)
+#define GPIO95_SM_PS0n         PIN_CFG(95, ALT_C)
+
+#define GPIO96_GPIO            PIN_CFG(96, GPIO)
+#define GPIO96_KP_O6           PIN_CFG(96, ALT_A)
+#define GPIO96_SM_OEn          PIN_CFG(96, ALT_B)
+#define GPIO96_MC5_DAT6                PIN_CFG(96, ALT_C)
+
+#define GPIO97_GPIO            PIN_CFG(97, GPIO)
+#define GPIO97_KP_I6           PIN_CFG(97, ALT_A)
+#define GPIO97_SM_WEn          PIN_CFG(97, ALT_B)
+#define GPIO97_MC5_DAT7                PIN_CFG(97, ALT_C)
+
+#define GPIO128_GPIO           PIN_CFG(128, GPIO)
+#define GPIO128_MC2_CLK                PIN_CFG(128, ALT_A)
+#define GPIO128_SM_CKO         PIN_CFG(128, ALT_B)
+
+#define GPIO129_GPIO           PIN_CFG(129, GPIO)
+#define GPIO129_MC2_CMD                PIN_CFG(129, ALT_A)
+#define GPIO129_SM_WAIT0n      PIN_CFG(129, ALT_B)
+
+#define GPIO130_GPIO           PIN_CFG(130, GPIO)
+#define GPIO130_MC2_FBCLK      PIN_CFG(130, ALT_A)
+#define GPIO130_SM_FBCLK       PIN_CFG(130, ALT_B)
+#define GPIO130_MC2_RSTN       PIN_CFG(130, ALT_C)
+
+#define GPIO131_GPIO           PIN_CFG(131, GPIO)
+#define GPIO131_MC2_DAT0       PIN_CFG(131, ALT_A)
+#define GPIO131_SM_ADQ8                PIN_CFG(131, ALT_B)
+
+#define GPIO132_GPIO           PIN_CFG(132, GPIO)
+#define GPIO132_MC2_DAT1       PIN_CFG(132, ALT_A)
+#define GPIO132_SM_ADQ9                PIN_CFG(132, ALT_B)
+
+#define GPIO133_GPIO           PIN_CFG(133, GPIO)
+#define GPIO133_MC2_DAT2       PIN_CFG(133, ALT_A)
+#define GPIO133_SM_ADQ10       PIN_CFG(133, ALT_B)
+
+#define GPIO134_GPIO           PIN_CFG(134, GPIO)
+#define GPIO134_MC2_DAT3       PIN_CFG(134, ALT_A)
+#define GPIO134_SM_ADQ11       PIN_CFG(134, ALT_B)
+
+#define GPIO135_GPIO           PIN_CFG(135, GPIO)
+#define GPIO135_MC2_DAT4       PIN_CFG(135, ALT_A)
+#define GPIO135_SM_ADQ12       PIN_CFG(135, ALT_B)
+
+#define GPIO136_GPIO           PIN_CFG(136, GPIO)
+#define GPIO136_MC2_DAT5       PIN_CFG(136, ALT_A)
+#define GPIO136_SM_ADQ13       PIN_CFG(136, ALT_B)
+
+#define GPIO137_GPIO           PIN_CFG(137, GPIO)
+#define GPIO137_MC2_DAT6       PIN_CFG(137, ALT_A)
+#define GPIO137_SM_ADQ14       PIN_CFG(137, ALT_B)
+
+#define GPIO138_GPIO           PIN_CFG(138, GPIO)
+#define GPIO138_MC2_DAT7       PIN_CFG(138, ALT_A)
+#define GPIO138_SM_ADQ15       PIN_CFG(138, ALT_B)
+
+#define GPIO139_GPIO           PIN_CFG(139, GPIO)
+#define GPIO139_SSP1_RXD       PIN_CFG(139, ALT_A)
+#define GPIO139_SM_WAIT1n      PIN_CFG(139, ALT_B)
+#define GPIO139_KP_O8          PIN_CFG(139, ALT_C)
+
+#define GPIO140_GPIO           PIN_CFG(140, GPIO)
+#define GPIO140_SSP1_TXD       PIN_CFG(140, ALT_A)
+#define GPIO140_IP_GPIO7       PIN_CFG(140, ALT_B)
+#define GPIO140_KP_SKA1                PIN_CFG(140, ALT_C)
+
+#define GPIO141_GPIO           PIN_CFG(141, GPIO)
+#define GPIO141_SSP1_CLK       PIN_CFG(141, ALT_A)
+#define GPIO141_IP_GPIO2       PIN_CFG(141, ALT_B)
+#define GPIO141_KP_O9          PIN_CFG(141, ALT_C)
+
+#define GPIO142_GPIO           PIN_CFG(142, GPIO)
+#define GPIO142_SSP1_FRM       PIN_CFG(142, ALT_A)
+#define GPIO142_IP_GPIO3       PIN_CFG(142, ALT_B)
+#define GPIO142_KP_SKB1                PIN_CFG(142, ALT_C)
+
+#define GPIO143_GPIO           PIN_CFG(143, GPIO)
+#define GPIO143_SSP0_CLK       PIN_CFG(143, ALT_A)
+
+#define GPIO144_GPIO           PIN_CFG(144, GPIO)
+#define GPIO144_SSP0_FRM       PIN_CFG(144, ALT_A)
+
+#define GPIO145_GPIO           PIN_CFG(145, GPIO)
+#define GPIO145_SSP0_RXD       PIN_CFG(145, ALT_A)
+
+#define GPIO146_GPIO           PIN_CFG(146, GPIO)
+#define GPIO146_SSP0_TXD       PIN_CFG(146, ALT_A)
+
+#define GPIO147_GPIO           PIN_CFG(147, GPIO)
+#define GPIO147_I2C0_SCL       PIN_CFG_PULL(147, ALT_A, UP)
+
+#define GPIO148_GPIO           PIN_CFG(148, GPIO)
+#define GPIO148_I2C0_SDA       PIN_CFG_PULL(148, ALT_A, UP)
+
+#define GPIO149_GPIO           PIN_CFG(149, GPIO)
+#define GPIO149_IP_GPIO0       PIN_CFG(149, ALT_A)
+#define GPIO149_SM_CS1n                PIN_CFG(149, ALT_B)
+#define GPIO149_SM_PS1n                PIN_CFG(149, ALT_C)
+
+#define GPIO150_GPIO           PIN_CFG(150, GPIO)
+#define GPIO150_IP_GPIO1       PIN_CFG(150, ALT_A)
+#define GPIO150_LCDA_CLK       PIN_CFG(150, ALT_B)
+
+#define GPIO151_GPIO           PIN_CFG(151, GPIO)
+#define GPIO151_KP_SKA0                PIN_CFG(151, ALT_A)
+#define GPIO151_LCD_VSI0       PIN_CFG(151, ALT_B)
+#define GPIO151_KP_O8          PIN_CFG(151, ALT_C)
+
+#define GPIO152_GPIO           PIN_CFG(152, GPIO)
+#define GPIO152_KP_SKB0                PIN_CFG(152, ALT_A)
+#define GPIO152_LCD_VSI1       PIN_CFG(152, ALT_B)
+#define GPIO152_KP_O9          PIN_CFG(152, ALT_C)
+
+#define GPIO153_GPIO           PIN_CFG(153, GPIO)
+#define GPIO153_KP_I7          PIN_CFG(153, ALT_A)
+#define GPIO153_LCD_D24                PIN_CFG(153, ALT_B)
+#define GPIO153_U2_RXD         PIN_CFG(153, ALT_C)
+
+#define GPIO154_GPIO           PIN_CFG(154, GPIO)
+#define GPIO154_KP_I6          PIN_CFG(154, ALT_A)
+#define GPIO154_LCD_D25                PIN_CFG(154, ALT_B)
+#define GPIO154_U2_TXD         PIN_CFG(154, ALT_C)
+
+#define GPIO155_GPIO           PIN_CFG(155, GPIO)
+#define GPIO155_KP_I5          PIN_CFG(155, ALT_A)
+#define GPIO155_LCD_D26                PIN_CFG(155, ALT_B)
+#define GPIO155_STMAPE_CLK     PIN_CFG(155, ALT_C)
+
+#define GPIO156_GPIO           PIN_CFG(156, GPIO)
+#define GPIO156_KP_I4          PIN_CFG(156, ALT_A)
+#define GPIO156_LCD_D27                PIN_CFG(156, ALT_B)
+#define GPIO156_STMAPE_DAT3    PIN_CFG(156, ALT_C)
+
+#define GPIO157_GPIO           PIN_CFG(157, GPIO)
+#define GPIO157_KP_O7          PIN_CFG(157, ALT_A)
+#define GPIO157_LCD_D28                PIN_CFG(157, ALT_B)
+#define GPIO157_STMAPE_DAT2    PIN_CFG(157, ALT_C)
+
+#define GPIO158_GPIO           PIN_CFG(158, GPIO)
+#define GPIO158_KP_O6          PIN_CFG(158, ALT_A)
+#define GPIO158_LCD_D29                PIN_CFG(158, ALT_B)
+#define GPIO158_STMAPE_DAT1    PIN_CFG(158, ALT_C)
+
+#define GPIO159_GPIO           PIN_CFG(159, GPIO)
+#define GPIO159_KP_O5          PIN_CFG(159, ALT_A)
+#define GPIO159_LCD_D30                PIN_CFG(159, ALT_B)
+#define GPIO159_STMAPE_DAT0    PIN_CFG(159, ALT_C)
+
+#define GPIO160_GPIO           PIN_CFG(160, GPIO)
+#define GPIO160_KP_O4          PIN_CFG(160, ALT_A)
+#define GPIO160_LCD_D31                PIN_CFG(160, ALT_B)
+#define GPIO160_NONE           PIN_CFG(160, ALT_C)
+
+#define GPIO161_GPIO           PIN_CFG(161, GPIO)
+#define GPIO161_KP_I3          PIN_CFG(161, ALT_A)
+#define GPIO161_LCD_D32                PIN_CFG(161, ALT_B)
+#define GPIO161_UARTMOD_RXD    PIN_CFG(161, ALT_C)
+
+#define GPIO162_GPIO           PIN_CFG(162, GPIO)
+#define GPIO162_KP_I2          PIN_CFG(162, ALT_A)
+#define GPIO162_LCD_D33                PIN_CFG(162, ALT_B)
+#define GPIO162_UARTMOD_TXD    PIN_CFG(162, ALT_C)
+
+#define GPIO163_GPIO           PIN_CFG(163, GPIO)
+#define GPIO163_KP_I1          PIN_CFG(163, ALT_A)
+#define GPIO163_LCD_D34                PIN_CFG(163, ALT_B)
+#define GPIO163_STMMOD_CLK     PIN_CFG(163, ALT_C)
+
+#define GPIO164_GPIO           PIN_CFG(164, GPIO)
+#define GPIO164_KP_I0          PIN_CFG(164, ALT_A)
+#define GPIO164_LCD_D35                PIN_CFG(164, ALT_B)
+#define GPIO164_STMMOD_DAT3    PIN_CFG(164, ALT_C)
+
+#define GPIO165_GPIO           PIN_CFG(165, GPIO)
+#define GPIO165_KP_O3          PIN_CFG(165, ALT_A)
+#define GPIO165_LCD_D36                PIN_CFG(165, ALT_B)
+#define GPIO165_STMMOD_DAT2    PIN_CFG(165, ALT_C)
+
+#define GPIO166_GPIO           PIN_CFG(166, GPIO)
+#define GPIO166_KP_O2          PIN_CFG(166, ALT_A)
+#define GPIO166_LCD_D37                PIN_CFG(166, ALT_B)
+#define GPIO166_STMMOD_DAT1    PIN_CFG(166, ALT_C)
+
+#define GPIO167_GPIO           PIN_CFG(167, GPIO)
+#define GPIO167_KP_O1          PIN_CFG(167, ALT_A)
+#define GPIO167_LCD_D38                PIN_CFG(167, ALT_B)
+#define GPIO167_STMMOD_DAT0    PIN_CFG(167, ALT_C)
+
+#define GPIO168_GPIO           PIN_CFG(168, GPIO)
+#define GPIO168_KP_O0          PIN_CFG(168, ALT_A)
+#define GPIO168_LCD_D39                PIN_CFG(168, ALT_B)
+#define GPIO168_NONE           PIN_CFG(168, ALT_C)
+
+#define GPIO169_GPIO           PIN_CFG(169, GPIO)
+#define GPIO169_RF_PURn                PIN_CFG(169, ALT_A)
+#define GPIO169_LCDA_DE                PIN_CFG(169, ALT_B)
+#define GPIO169_USBSIM_PDC     PIN_CFG(169, ALT_C)
+
+#define GPIO170_GPIO           PIN_CFG(170, GPIO)
+#define GPIO170_MODEM_STATE    PIN_CFG(170, ALT_A)
+#define GPIO170_LCDA_VSO       PIN_CFG(170, ALT_B)
+#define GPIO170_KP_SKA1                PIN_CFG(170, ALT_C)
+
+#define GPIO171_GPIO           PIN_CFG(171, GPIO)
+#define GPIO171_MODEM_PWREN    PIN_CFG(171, ALT_A)
+#define GPIO171_LCDA_HSO       PIN_CFG(171, ALT_B)
+#define GPIO171_KP_SKB1                PIN_CFG(171, ALT_C)
+
+#define GPIO192_GPIO           PIN_CFG(192, GPIO)
+#define GPIO192_MSP2_SCK       PIN_CFG(192, ALT_A)
+
+#define GPIO193_GPIO           PIN_CFG(193, GPIO)
+#define GPIO193_MSP2_TXD       PIN_CFG(193, ALT_A)
+
+#define GPIO194_GPIO           PIN_CFG(194, GPIO)
+#define GPIO194_MSP2_TCK       PIN_CFG(194, ALT_A)
+
+#define GPIO195_GPIO           PIN_CFG(195, GPIO)
+#define GPIO195_MSP2_TFS       PIN_CFG(195, ALT_A)
+
+#define GPIO196_GPIO           PIN_CFG(196, GPIO)
+#define GPIO196_MSP2_RXD       PIN_CFG(196, ALT_A)
+
+#define GPIO197_GPIO           PIN_CFG(197, GPIO)
+#define GPIO197_MC4_DAT3       PIN_CFG(197, ALT_A)
+
+#define GPIO198_GPIO           PIN_CFG(198, GPIO)
+#define GPIO198_MC4_DAT2       PIN_CFG(198, ALT_A)
+
+#define GPIO199_GPIO           PIN_CFG(199, GPIO)
+#define GPIO199_MC4_DAT1       PIN_CFG(199, ALT_A)
+
+#define GPIO200_GPIO           PIN_CFG(200, GPIO)
+#define GPIO200_MC4_DAT0       PIN_CFG(200, ALT_A)
+
+#define GPIO201_GPIO           PIN_CFG(201, GPIO)
+#define GPIO201_MC4_CMD                PIN_CFG(201, ALT_A)
+
+#define GPIO202_GPIO           PIN_CFG(202, GPIO)
+#define GPIO202_MC4_FBCLK      PIN_CFG(202, ALT_A)
+#define GPIO202_PWL            PIN_CFG(202, ALT_B)
+#define GPIO202_MC4_RSTN       PIN_CFG(202, ALT_C)
+
+#define GPIO203_GPIO           PIN_CFG(203, GPIO)
+#define GPIO203_MC4_CLK                PIN_CFG(203, ALT_A)
+
+#define GPIO204_GPIO           PIN_CFG(204, GPIO)
+#define GPIO204_MC4_DAT7       PIN_CFG(204, ALT_A)
+
+#define GPIO205_GPIO           PIN_CFG(205, GPIO)
+#define GPIO205_MC4_DAT6       PIN_CFG(205, ALT_A)
+
+#define GPIO206_GPIO           PIN_CFG(206, GPIO)
+#define GPIO206_MC4_DAT5       PIN_CFG(206, ALT_A)
+
+#define GPIO207_GPIO           PIN_CFG(207, GPIO)
+#define GPIO207_MC4_DAT4       PIN_CFG(207, ALT_A)
+
+#define GPIO208_GPIO           PIN_CFG(208, GPIO)
+#define GPIO208_MC1_CLK                PIN_CFG(208, ALT_A)
+
+#define GPIO209_GPIO           PIN_CFG(209, GPIO)
+#define GPIO209_MC1_FBCLK      PIN_CFG(209, ALT_A)
+#define GPIO209_SPI1_CLK       PIN_CFG(209, ALT_B)
+
+#define GPIO210_GPIO           PIN_CFG(210, GPIO)
+#define GPIO210_MC1_CMD                PIN_CFG(210, ALT_A)
+
+#define GPIO211_GPIO           PIN_CFG(211, GPIO)
+#define GPIO211_MC1_DAT0       PIN_CFG(211, ALT_A)
+
+#define GPIO212_GPIO           PIN_CFG(212, GPIO)
+#define GPIO212_MC1_DAT1       PIN_CFG(212, ALT_A)
+#define GPIO212_SPI1_FRM       PIN_CFG(212, ALT_B)
+
+#define GPIO213_GPIO           PIN_CFG(213, GPIO)
+#define GPIO213_MC1_DAT2       PIN_CFG(213, ALT_A)
+#define GPIO213_SPI1_TXD       PIN_CFG(213, ALT_B)
+
+#define GPIO214_GPIO           PIN_CFG(214, GPIO)
+#define GPIO214_MC1_DAT3       PIN_CFG(214, ALT_A)
+#define GPIO214_SPI1_RXD       PIN_CFG(214, ALT_B)
+
+#define GPIO215_GPIO           PIN_CFG(215, GPIO)
+#define GPIO215_MC1_CMDDIR     PIN_CFG(215, ALT_A)
+#define GPIO215_MC3_DAT2DIR    PIN_CFG(215, ALT_B)
+#define GPIO215_CLKOUT1                PIN_CFG(215, ALT_C)
+
+#define GPIO216_GPIO           PIN_CFG(216, GPIO)
+#define GPIO216_MC1_DAT2DIR    PIN_CFG(216, ALT_A)
+#define GPIO216_MC3_CMDDIR     PIN_CFG(216, ALT_B)
+#define GPIO216_I2C3_SDA       PIN_CFG_PULL(216, ALT_C, UP)
+
+#define GPIO217_GPIO           PIN_CFG(217, GPIO)
+#define GPIO217_MC1_DAT0DIR    PIN_CFG(217, ALT_A)
+#define GPIO217_MC3_DAT31DIR   PIN_CFG(217, ALT_B)
+#define GPIO217_CLKOUT2                PIN_CFG(217, ALT_C)
+
+#define GPIO218_GPIO           PIN_CFG(218, GPIO)
+#define GPIO218_MC1_DAT31DIR   PIN_CFG(218, ALT_A)
+#define GPIO218_MC3_DAT0DIR    PIN_CFG(218, ALT_B)
+#define GPIO218_I2C3_SCL       PIN_CFG_PULL(218, ALT_C, UP)
+
+#define GPIO219_GPIO           PIN_CFG(219, GPIO)
+#define GPIO219_HSIR_FLA0      PIN_CFG(219, ALT_A)
+#define GPIO219_MC3_CLK                PIN_CFG(219, ALT_B)
+
+#define GPIO220_GPIO           PIN_CFG(220, GPIO)
+#define GPIO220_HSIR_DAT0      PIN_CFG(220, ALT_A)
+#define GPIO220_MC3_FBCLK      PIN_CFG(220, ALT_B)
+#define GPIO220_SPI0_CLK       PIN_CFG(220, ALT_C)
+
+#define GPIO221_GPIO           PIN_CFG(221, GPIO)
+#define GPIO221_HSIR_RDY0      PIN_CFG(221, ALT_A)
+#define GPIO221_MC3_CMD                PIN_CFG(221, ALT_B)
+
+#define GPIO222_GPIO           PIN_CFG(222, GPIO)
+#define GPIO222_HSIT_FLA0      PIN_CFG(222, ALT_A)
+#define GPIO222_MC3_DAT0       PIN_CFG(222, ALT_B)
+
+#define GPIO223_GPIO           PIN_CFG(223, GPIO)
+#define GPIO223_HSIT_DAT0      PIN_CFG(223, ALT_A)
+#define GPIO223_MC3_DAT1       PIN_CFG(223, ALT_B)
+#define GPIO223_SPI0_FRM       PIN_CFG(223, ALT_C)
+
+#define GPIO224_GPIO           PIN_CFG(224, GPIO)
+#define GPIO224_HSIT_RDY0      PIN_CFG(224, ALT_A)
+#define GPIO224_MC3_DAT2       PIN_CFG(224, ALT_B)
+#define GPIO224_SPI0_TXD       PIN_CFG(224, ALT_C)
+
+#define GPIO225_GPIO           PIN_CFG(225, GPIO)
+#define GPIO225_HSIT_CAWAKE0   PIN_CFG(225, ALT_A)
+#define GPIO225_MC3_DAT3       PIN_CFG(225, ALT_B)
+#define GPIO225_SPI0_RXD       PIN_CFG(225, ALT_C)
+
+#define GPIO226_GPIO           PIN_CFG(226, GPIO)
+#define GPIO226_HSIT_ACWAKE0   PIN_CFG(226, ALT_A)
+#define GPIO226_PWL            PIN_CFG(226, ALT_B)
+#define GPIO226_USBSIM_PDC     PIN_CFG(226, ALT_C)
+
+#define GPIO227_GPIO           PIN_CFG(227, GPIO)
+#define GPIO227_CLKOUT1                PIN_CFG(227, ALT_A)
+
+#define GPIO228_GPIO           PIN_CFG(228, GPIO)
+#define GPIO228_CLKOUT2                PIN_CFG(228, ALT_A)
+
+#define GPIO229_GPIO           PIN_CFG(229, GPIO)
+#define GPIO229_CLKOUT1                PIN_CFG(229, ALT_A)
+#define GPIO229_PWL            PIN_CFG(229, ALT_B)
+#define GPIO229_I2C3_SDA       PIN_CFG_PULL(229, ALT_C, UP)
+
+#define GPIO230_GPIO           PIN_CFG(230, GPIO)
+#define GPIO230_CLKOUT2                PIN_CFG(230, ALT_A)
+#define GPIO230_PWL            PIN_CFG(230, ALT_B)
+#define GPIO230_I2C3_SCL       PIN_CFG_PULL(230, ALT_C, UP)
+
+#define GPIO256_GPIO           PIN_CFG(256, GPIO)
+#define GPIO256_USB_NXT                PIN_CFG(256, ALT_A)
+
+#define GPIO257_GPIO           PIN_CFG(257, GPIO)
+#define GPIO257_USB_STP                PIN_CFG(257, ALT_A)
+
+#define GPIO258_GPIO           PIN_CFG(258, GPIO)
+#define GPIO258_USB_XCLK       PIN_CFG(258, ALT_A)
+#define GPIO258_NONE           PIN_CFG(258, ALT_B)
+#define GPIO258_DDR_TRIG       PIN_CFG(258, ALT_C)
+
+#define GPIO259_GPIO           PIN_CFG(259, GPIO)
+#define GPIO259_USB_DIR                PIN_CFG(259, ALT_A)
+
+#define GPIO260_GPIO           PIN_CFG(260, GPIO)
+#define GPIO260_USB_DAT7       PIN_CFG(260, ALT_A)
+
+#define GPIO261_GPIO           PIN_CFG(261, GPIO)
+#define GPIO261_USB_DAT6       PIN_CFG(261, ALT_A)
+
+#define GPIO262_GPIO           PIN_CFG(262, GPIO)
+#define GPIO262_USB_DAT5       PIN_CFG(262, ALT_A)
+
+#define GPIO263_GPIO           PIN_CFG(263, GPIO)
+#define GPIO263_USB_DAT4       PIN_CFG(263, ALT_A)
+
+#define GPIO264_GPIO           PIN_CFG(264, GPIO)
+#define GPIO264_USB_DAT3       PIN_CFG(264, ALT_A)
+
+#define GPIO265_GPIO           PIN_CFG(265, GPIO)
+#define GPIO265_USB_DAT2       PIN_CFG(265, ALT_A)
+
+#define GPIO266_GPIO           PIN_CFG(266, GPIO)
+#define GPIO266_USB_DAT1       PIN_CFG(266, ALT_A)
+
+#define GPIO267_GPIO           PIN_CFG(267, GPIO)
+#define GPIO267_USB_DAT0       PIN_CFG(267, ALT_A)
+
+#endif
index 3dff8641b03fa7a639d5f886345dad1e84706445..e38acb0f89c884b961bdb1dc11fa59b1a0112bc0 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/amba/clcd.h>
 #include <linux/amba/pl061.h>
 #include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
 #include <linux/io.h>
 #include <linux/gfp.h>
 
@@ -354,6 +355,21 @@ static struct mmci_platform_data mmc0_plat_data = {
        .gpio_cd        = -1,
 };
 
+static struct resource char_lcd_resources[] = {
+       {
+               .start = VERSATILE_CHAR_LCD_BASE,
+               .end   = (VERSATILE_CHAR_LCD_BASE + SZ_4K - 1),
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device char_lcd_device = {
+       .name           =       "arm-charlcd",
+       .id             =       -1,
+       .num_resources  =       ARRAY_SIZE(char_lcd_resources),
+       .resource       =       char_lcd_resources,
+};
+
 /*
  * Clock handling
  */
@@ -400,8 +416,13 @@ static struct clk ref24_clk = {
        .rate   = 24000000,
 };
 
+static struct clk dummy_apb_pclk;
+
 static struct clk_lookup lookups[] = {
-       {       /* UART0 */
+       {       /* AMBA bus clock */
+               .con_id         = "apb_pclk",
+               .clk            = &dummy_apb_pclk,
+       }, {    /* UART0 */
                .dev_id         = "dev:f1",
                .clk            = &ref24_clk,
        }, {    /* UART1 */
@@ -425,6 +446,9 @@ static struct clk_lookup lookups[] = {
        }, {    /* MMC1 */
                .dev_id         = "fpga:0b",
                .clk            = &ref24_clk,
+       }, {    /* SSP */
+               .dev_id         = "dev:f4",
+               .clk            = &ref24_clk,
        }, {    /* CLCD */
                .dev_id         = "dev:20",
                .clk            = &osc4_clk,
@@ -703,6 +727,12 @@ static struct pl061_platform_data gpio1_plat_data = {
        .irq_base       = IRQ_GPIO1_START,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+       .bus_id = 0,
+       .enable_dma = 0,
+       .num_chipselect = 1,
+};
+
 #define AACI_IRQ       { IRQ_AACI, NO_IRQ }
 #define AACI_DMA       { 0x80, 0x81 }
 #define MMCI0_IRQ      { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
@@ -772,7 +802,7 @@ AMBA_DEVICE(sci0,  "dev:f0",  SCI,      NULL);
 AMBA_DEVICE(uart0, "dev:f1",  UART0,    NULL);
 AMBA_DEVICE(uart1, "dev:f2",  UART1,    NULL);
 AMBA_DEVICE(uart2, "dev:f3",  UART2,    NULL);
-AMBA_DEVICE(ssp0,  "dev:f4",  SSP,      NULL);
+AMBA_DEVICE(ssp0,  "dev:f4",  SSP,      &ssp0_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
@@ -843,6 +873,7 @@ void __init versatile_init(void)
        platform_device_register(&versatile_flash_device);
        platform_device_register(&versatile_i2c_device);
        platform_device_register(&smc91x_device);
+       platform_device_register(&char_lcd_device);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
index 334f0df4e948bc46c322c3ca0c50fe8002b676c0..13c7e5f90a82eb1d4f52883e784eea8d08257546 100644 (file)
@@ -304,7 +304,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 }
 
 
-struct pci_bus *pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus * __init pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
 {
        return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys);
 }
index 6353459bb5671bc2623377529b9a6dfcd5db4a8f..577df6cccb0891503bf0188f3c0f33103c159000 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 #include <asm/pmu.h>
+#include <asm/smp_twd.h>
 
 #include <mach/clkdev.h>
 #include <mach/ct-ca9x4.h>
@@ -53,6 +54,7 @@ static struct map_desc ct_ca9x4_io_desc[] __initdata = {
 
 static void __init ct_ca9x4_map_io(void)
 {
+       twd_base = MMIO_P2V(A9_MPCORE_TWD);
        v2m_map_io(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
index 8650f04136efa0e744edb230f4d94afb1325f755..f9e2f8d229623d5825251e1999b0bf501a18b4a6 100644 (file)
@@ -28,6 +28,7 @@
 #define A9_MPCORE_SCU          (CT_CA9X4_MPIC + 0x0000)
 #define A9_MPCORE_GIC_CPU      (CT_CA9X4_MPIC + 0x0100)
 #define A9_MPCORE_GIT          (CT_CA9X4_MPIC + 0x0200)
+#define A9_MPCORE_TWD          (CT_CA9X4_MPIC + 0x0600)
 #define A9_MPCORE_GIC_DIST     (CT_CA9X4_MPIC + 0x1000)
 
 /*
index d250711b8c7a4e3c17ee2ddcc53ad5b2e24ee420..817f0ad38a0b5100ec0884e8c908c84af471bec4 100644 (file)
@@ -241,7 +241,7 @@ static struct platform_device v2m_flash_device = {
 
 static unsigned int v2m_mmci_status(struct device *dev)
 {
-       return !(readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0));
+       return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0);
 }
 
 static struct mmci_platform_data v2m_mmci_data = {
@@ -298,8 +298,13 @@ static struct clk osc2_clk = {
        .rate   = 24000000,
 };
 
+static struct clk dummy_apb_pclk;
+
 static struct clk_lookup v2m_lookups[] = {
-       {       /* UART0 */
+       {       /* AMBA bus clock */
+               .con_id         = "apb_pclk",
+               .clk            = &dummy_apb_pclk,
+       }, {    /* UART0 */
                .dev_id         = "mb:uart0",
                .clk            = &osc2_clk,
        }, {    /* UART1 */
index b2eda4dc1c34ea7172a773899275c18bbfab5dd4..7a1fa6adb7c32d5645b1f0e608b1e61794081afc 100644 (file)
@@ -36,6 +36,8 @@
 #include <mach/nuc900_spi.h>
 #include <mach/map.h>
 #include <mach/fb.h>
+#include <mach/regs-ldm.h>
+#include <mach/w90p910_keypad.h>
 
 #include "cpu.h"
 
@@ -207,7 +209,7 @@ static struct nuc900_spi_info nuc900_spiflash_data = {
        .divider        = 24,
        .sleep          = 0,
        .txnum          = 0,
-       .txbitlen       = 1,
+       .txbitlen       = 8,
        .bus_num        = 0,
 };
 
@@ -256,7 +258,7 @@ static struct spi_board_info nuc900_spi_board_info[] __initdata = {
                .modalias = "m25p80",
                .max_speed_hz = 20000000,
                .bus_num = 0,
-               .chip_select = 1,
+               .chip_select = 0,
                .platform_data = &nuc900_spi_flash_data,
                .mode = SPI_MODE_0,
        },
@@ -361,6 +363,39 @@ struct platform_device nuc900_device_fmi = {
 
 /* KPI controller*/
 
+static int nuc900_keymap[] = {
+       KEY(0, 0, KEY_A),
+       KEY(0, 1, KEY_B),
+       KEY(0, 2, KEY_C),
+       KEY(0, 3, KEY_D),
+
+       KEY(1, 0, KEY_E),
+       KEY(1, 1, KEY_F),
+       KEY(1, 2, KEY_G),
+       KEY(1, 3, KEY_H),
+
+       KEY(2, 0, KEY_I),
+       KEY(2, 1, KEY_J),
+       KEY(2, 2, KEY_K),
+       KEY(2, 3, KEY_L),
+
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P),
+};
+
+static struct matrix_keymap_data nuc900_map_data = {
+       .keymap                 = nuc900_keymap,
+       .keymap_size            = ARRAY_SIZE(nuc900_keymap),
+};
+
+struct w90p910_keypad_platform_data nuc900_keypad_info = {
+       .keymap_data    = &nuc900_map_data,
+       .prescale       = 0xfa,
+       .debounce       = 0x50,
+};
+
 static struct resource nuc900_kpi_resource[] = {
        [0] = {
                .start = W90X900_PA_KPI,
@@ -380,9 +415,49 @@ struct platform_device nuc900_device_kpi = {
        .id             = -1,
        .num_resources  = ARRAY_SIZE(nuc900_kpi_resource),
        .resource       = nuc900_kpi_resource,
+       .dev            = {
+                               .platform_data = &nuc900_keypad_info,
+                       }
 };
 
-#ifdef CONFIG_FB_NUC900
+/* LCD controller*/
+
+static struct nuc900fb_display __initdata nuc900_lcd_info[] = {
+       /* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */
+       [0] = {
+               .type           = LCM_DCCS_VA_SRC_RGB565,
+               .width          = 320,
+               .height         = 240,
+               .xres           = 320,
+               .yres           = 240,
+               .bpp            = 16,
+               .pixclock       = 200000,
+               .left_margin    = 34,
+               .right_margin   = 54,
+               .hsync_len      = 10,
+               .upper_margin   = 18,
+               .lower_margin   = 4,
+               .vsync_len      = 1,
+               .dccs           = 0x8e00041a,
+               .devctl         = 0x060800c0,
+               .fbctrl         = 0x00a000a0,
+               .scale          = 0x04000400,
+       },
+};
+
+static struct nuc900fb_mach_info nuc900_fb_info __initdata = {
+#if defined(CONFIG_GPM1040A0_320X240)
+       .displays               = &nuc900_lcd_info[0],
+#else
+       .displays               = nuc900_lcd_info,
+#endif
+       .num_displays           = ARRAY_SIZE(nuc900_lcd_info),
+       .default_display        = 0,
+       .gpio_dir               = 0x00000004,
+       .gpio_dir_mask          = 0xFFFFFFFD,
+       .gpio_data              = 0x00000004,
+       .gpio_data_mask         = 0xFFFFFFFD,
+};
 
 static struct resource nuc900_lcd_resource[] = {
        [0] = {
@@ -406,23 +481,10 @@ struct platform_device nuc900_device_lcd = {
        .dev              = {
                .dma_mask               = &nuc900_device_lcd_dmamask,
                .coherent_dma_mask      = -1,
+               .platform_data = &nuc900_fb_info,
        }
 };
 
-void  nuc900_fb_set_platdata(struct nuc900fb_mach_info *pd)
-{
-       struct nuc900fb_mach_info *npd;
-
-       npd = kmalloc(sizeof(*npd), GFP_KERNEL);
-       if (npd) {
-               memcpy(npd, pd, sizeof(*npd));
-               nuc900_device_lcd.dev.platform_data = npd;
-       } else {
-               printk(KERN_ERR "no memory for LCD platform data\n");
-       }
-}
-#endif
-
 /* AUDIO controller*/
 static u64 nuc900_device_audio_dmamask = -1;
 static struct resource nuc900_ac97_resource[] = {
diff --git a/arch/arm/mach-w90x900/include/mach/regs-gcr.h b/arch/arm/mach-w90x900/include/mach/regs-gcr.h
new file mode 100644 (file)
index 0000000..6087abd
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-gcr.h
+ *
+ * Copyright (c) 2010 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@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.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_GCR_H
+#define __ASM_ARCH_REGS_GCR_H
+
+/* Global control registers */
+
+#define GCR_BA         W90X900_VA_GCR
+#define REG_PDID       (GCR_BA+0x000)
+#define REG_PWRON      (GCR_BA+0x004)
+#define REG_ARBCON     (GCR_BA+0x008)
+#define REG_MFSEL      (GCR_BA+0x00C)
+#define REG_EBIDPE     (GCR_BA+0x010)
+#define REG_LCDDPE     (GCR_BA+0x014)
+#define REG_GPIOCPE    (GCR_BA+0x018)
+#define REG_GPIODPE    (GCR_BA+0x01C)
+#define REG_GPIOEPE    (GCR_BA+0x020)
+#define REG_GPIOFPE    (GCR_BA+0x024)
+#define REG_GPIOGPE    (GCR_BA+0x028)
+#define REG_GPIOHPE    (GCR_BA+0x02C)
+#define REG_GPIOIPE    (GCR_BA+0x030)
+#define REG_GTMP1      (GCR_BA+0x034)
+#define REG_GTMP2      (GCR_BA+0x038)
+#define REG_GTMP3      (GCR_BA+0x03C)
+
+#endif /*  __ASM_ARCH_REGS_GCR_H */
index b3edc3cccf52f4c152ce9008e4d92fcc157c1584..04d295f89eb049f86ed0b8c6ba8386c5d0c0c09e 100644 (file)
 #include <asm/mach/map.h>
 #include <asm/mach-types.h>
 #include <mach/map.h>
-#include <mach/regs-ldm.h>
 #include <mach/fb.h>
 
 #include "nuc950.h"
 
-#ifdef CONFIG_FB_NUC900
-/* LCD Controller */
-static struct nuc900fb_display __initdata nuc950_lcd_info[] = {
-       /* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */
-       [0] = {
-               .type           = LCM_DCCS_VA_SRC_RGB565,
-               .width          = 320,
-               .height         = 240,
-               .xres           = 320,
-               .yres           = 240,
-               .bpp            = 16,
-               .pixclock       = 200000,
-               .left_margin    = 34,
-               .right_margin   = 54,
-               .hsync_len      = 10,
-               .upper_margin   = 18,
-               .lower_margin   = 4,
-               .vsync_len      = 1,
-               .dccs           = 0x8e00041a,
-               .devctl         = 0x060800c0,
-               .fbctrl         = 0x00a000a0,
-               .scale          = 0x04000400,
-       },
-};
-
-static struct nuc900fb_mach_info nuc950_fb_info __initdata = {
-#if defined(CONFIG_GPM1040A0_320X240)
-       .displays               = &nuc950_lcd_info[0],
-#else
-       .displays               = nuc950_lcd_info,
-#endif
-       .num_displays           = ARRAY_SIZE(nuc950_lcd_info),
-       .default_display        = 0,
-       .gpio_dir               = 0x00000004,
-       .gpio_dir_mask          = 0xFFFFFFFD,
-       .gpio_data              = 0x00000004,
-       .gpio_data_mask         = 0xFFFFFFFD,
-};
-#endif
-
 static void __init nuc950evb_map_io(void)
 {
        nuc950_map_io();
@@ -74,9 +33,6 @@ static void __init nuc950evb_map_io(void)
 static void __init nuc950evb_init(void)
 {
        nuc950_board_init();
-#ifdef CONFIG_FB_NUC900
-       nuc900_fb_set_platdata(&nuc950_fb_info);
-#endif
 }
 
 MACHINE_START(W90P950EVB, "W90P950EVB")
index 656f03b3b629f28e8972d983f652a406ef7d7e94..1523f41369857a95ad8669679bae3ecf88820a00 100644 (file)
@@ -26,6 +26,8 @@
 static struct platform_device *nuc910_dev[] __initdata = {
        &nuc900_device_ts,
        &nuc900_device_rtc,
+       &nuc900_device_lcd,
+       &nuc900_device_kpi,
 };
 
 /* define specific CPU platform io map */
index 4d1f1ab044c48868d588b6081d8ebcabad98c7b5..5704f74a50eeaf768667c07669108396fdcd1fe0 100644 (file)
@@ -26,9 +26,7 @@
 static struct platform_device *nuc950_dev[] __initdata = {
        &nuc900_device_kpi,
        &nuc900_device_fmi,
-#ifdef CONFIG_FB_NUC900
        &nuc900_device_lcd,
-#endif
 };
 
 /* define specific CPU platform io map */
index 101105e5261070118f8039c5ecbcde350792f38f..87ec141fcaa6e5ad0d5d7eef0e1a8249ac2bdcc3 100644 (file)
@@ -717,17 +717,6 @@ config TLS_REG_EMUL
          a few prototypes like that in existence) and therefore access to
          that required register must be emulated.
 
-config HAS_TLS_REG
-       bool
-       depends on !TLS_REG_EMUL
-       default y if SMP || CPU_32v7
-       help
-         This selects support for the CP15 thread register.
-         It is defined to be available on some ARMv6 processors (including
-         all SMP capable ARMv6's) or later processors.  User space may
-         assume directly accessing that register and always obtain the
-         expected value only on ARMv7 and above.
-
 config NEEDS_SYSCALL_FOR_CMPXCHG
        bool
        help
index e8d34a80851c66baf47c3d97e89e029e5e9a96ca..d63b6c413758a23389cbb09ea1ab8686c61e56db 100644 (file)
@@ -15,7 +15,6 @@ endif
 obj-$(CONFIG_MODULES)          += proc-syms.o
 
 obj-$(CONFIG_ALIGNMENT_TRAP)   += alignment.o
-obj-$(CONFIG_DISCONTIGMEM)     += discontig.o
 obj-$(CONFIG_HIGHMEM)          += highmem.o
 
 obj-$(CONFIG_CPU_ABRT_NOMMU)   += abort-nommu.o
index 6f98c358989a63347a6a1150f99f25b52b106dbe..d073b64ae87ec4f6652c67959244292dbb3e69ad 100644 (file)
@@ -924,8 +924,20 @@ static int __init alignment_init(void)
                ai_usermode = UM_FIXUP;
        }
 
-       hook_fault_code(1, do_alignment, SIGILL, "alignment exception");
-       hook_fault_code(3, do_alignment, SIGILL, "alignment exception");
+       hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
+                       "alignment exception");
+
+       /*
+        * ARMv6K and ARMv7 use fault status 3 (0b00011) as Access Flag section
+        * fault, not as alignment error.
+        *
+        * TODO: handle ARMv6K properly. Runtime check for 'K' extension is
+        * needed.
+        */
+       if (cpu_architecture() <= CPU_ARCH_ARMv6) {
+               hook_fault_code(3, do_alignment, SIGBUS, BUS_ADRALN,
+                               "alignment exception");
+       }
 
        return 0;
 }
index df4955885b21d412ede58df0a8c26a4fcb8ca0fb..9982eb385c0f9844d70f53d45c7377fcf5fa2887 100644 (file)
@@ -32,14 +32,14 @@ static uint32_t l2x0_way_mask;      /* Bitmask of active ways */
 static inline void cache_wait(void __iomem *reg, unsigned long mask)
 {
        /* wait for the operation to complete */
-       while (readl(reg) & mask)
+       while (readl_relaxed(reg) & mask)
                ;
 }
 
 static inline void cache_sync(void)
 {
        void __iomem *base = l2x0_base;
-       writel(0, base + L2X0_CACHE_SYNC);
+       writel_relaxed(0, base + L2X0_CACHE_SYNC);
        cache_wait(base + L2X0_CACHE_SYNC, 1);
 }
 
@@ -47,14 +47,14 @@ static inline void l2x0_clean_line(unsigned long addr)
 {
        void __iomem *base = l2x0_base;
        cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
-       writel(addr, base + L2X0_CLEAN_LINE_PA);
+       writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA);
 }
 
 static inline void l2x0_inv_line(unsigned long addr)
 {
        void __iomem *base = l2x0_base;
        cache_wait(base + L2X0_INV_LINE_PA, 1);
-       writel(addr, base + L2X0_INV_LINE_PA);
+       writel_relaxed(addr, base + L2X0_INV_LINE_PA);
 }
 
 #ifdef CONFIG_PL310_ERRATA_588369
@@ -75,9 +75,9 @@ static inline void l2x0_flush_line(unsigned long addr)
 
        /* Clean by PA followed by Invalidate by PA */
        cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
-       writel(addr, base + L2X0_CLEAN_LINE_PA);
+       writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA);
        cache_wait(base + L2X0_INV_LINE_PA, 1);
-       writel(addr, base + L2X0_INV_LINE_PA);
+       writel_relaxed(addr, base + L2X0_INV_LINE_PA);
 }
 #else
 
@@ -90,7 +90,7 @@ static inline void l2x0_flush_line(unsigned long addr)
 {
        void __iomem *base = l2x0_base;
        cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
-       writel(addr, base + L2X0_CLEAN_INV_LINE_PA);
+       writel_relaxed(addr, base + L2X0_CLEAN_INV_LINE_PA);
 }
 #endif
 
@@ -109,7 +109,7 @@ static inline void l2x0_inv_all(void)
 
        /* invalidate all ways */
        spin_lock_irqsave(&l2x0_lock, flags);
-       writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
+       writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
        cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
        cache_sync();
        spin_unlock_irqrestore(&l2x0_lock, flags);
@@ -215,8 +215,8 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
 
        l2x0_base = base;
 
-       cache_id = readl(l2x0_base + L2X0_CACHE_ID);
-       aux = readl(l2x0_base + L2X0_AUX_CTRL);
+       cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
+       aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 
        aux &= aux_mask;
        aux |= aux_val;
@@ -248,15 +248,15 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
         * If you are booting from non-secure mode
         * accessing the below registers will fault.
         */
-       if (!(readl(l2x0_base + L2X0_CTRL) & 1)) {
+       if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
 
                /* l2x0 controller is disabled */
-               writel(aux, l2x0_base + L2X0_AUX_CTRL);
+               writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
 
                l2x0_inv_all();
 
                /* enable L2X0 */
-               writel(1, l2x0_base + L2X0_CTRL);
+               writel_relaxed(1, l2x0_base + L2X0_CTRL);
        }
 
        outer_cache.inv_range = l2x0_inv_range;
diff --git a/arch/arm/mm/discontig.c b/arch/arm/mm/discontig.c
deleted file mode 100644 (file)
index c8c0c4b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/arch/arm/mm/discontig.c
- *
- * Discontiguous memory support.
- *
- * Initial code: Copyright (C) 1999-2000 Nicolas Pitre
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/mmzone.h>
-#include <linux/bootmem.h>
-
-#if MAX_NUMNODES != 4 && MAX_NUMNODES != 16
-# error Fix Me Please
-#endif
-
-/*
- * Our node_data structure for discontiguous memory.
- */
-
-pg_data_t discontig_node_data[MAX_NUMNODES] = {
-  { .bdata = &bootmem_node_data[0] },
-  { .bdata = &bootmem_node_data[1] },
-  { .bdata = &bootmem_node_data[2] },
-  { .bdata = &bootmem_node_data[3] },
-#if MAX_NUMNODES == 16
-  { .bdata = &bootmem_node_data[4] },
-  { .bdata = &bootmem_node_data[5] },
-  { .bdata = &bootmem_node_data[6] },
-  { .bdata = &bootmem_node_data[7] },
-  { .bdata = &bootmem_node_data[8] },
-  { .bdata = &bootmem_node_data[9] },
-  { .bdata = &bootmem_node_data[10] },
-  { .bdata = &bootmem_node_data[11] },
-  { .bdata = &bootmem_node_data[12] },
-  { .bdata = &bootmem_node_data[13] },
-  { .bdata = &bootmem_node_data[14] },
-  { .bdata = &bootmem_node_data[15] },
-#endif
-};
-
-EXPORT_SYMBOL(discontig_node_data);
index 9e7742f0a102fe5c7d091134391db81d93d71726..c704eed63c5ddba4c5f849f7ab7b6420008cef21 100644 (file)
@@ -183,6 +183,8 @@ static void *
 __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
 {
        struct arm_vmregion *c;
+       size_t align;
+       int bit;
 
        if (!consistent_pte[0]) {
                printk(KERN_ERR "%s: not initialised\n", __func__);
@@ -190,10 +192,21 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
                return NULL;
        }
 
+       /*
+        * Align the virtual region allocation - maximum alignment is
+        * a section size, minimum is a page size.  This helps reduce
+        * fragmentation of the DMA space, and also prevents allocations
+        * smaller than a section from crossing a section boundary.
+        */
+       bit = fls(size - 1) + 1;
+       if (bit > SECTION_SHIFT)
+               bit = SECTION_SHIFT;
+       align = 1 << bit;
+
        /*
         * Allocate a virtual address in the consistent mapping region.
         */
-       c = arm_vmregion_alloc(&consistent_head, size,
+       c = arm_vmregion_alloc(&consistent_head, align, size,
                            gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
        if (c) {
                pte_t *pte;
index cbfb2edcf7d12a3a1cae18f04c041d94dc055bcc..23b0b03af5ea84b8a01e10c59a97091d92f4618b 100644 (file)
@@ -413,7 +413,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
        pmd_k = pmd_offset(pgd_k, addr);
        pmd   = pmd_offset(pgd, addr);
 
-       if (pmd_none(*pmd_k))
+       /*
+        * On ARM one Linux PGD entry contains two hardware entries (see page
+        * tables layout in pgtable.h). We normally guarantee that we always
+        * fill both L1 entries. But create_mapping() doesn't follow the rule.
+        * It can create inidividual L1 entries, so here we have to call
+        * pmd_none() check for the entry really corresponded to address, not
+        * for the first of pair.
+        */
+       index = (addr >> SECTION_SHIFT) & 1;
+       if (pmd_none(pmd_k[index]))
                goto bad_area;
 
        copy_pmd(pmd, pmd_k);
@@ -463,15 +472,10 @@ static struct fsr_info {
         * defines these to be "precise" aborts.
         */
        { do_bad,               SIGSEGV, 0,             "vector exception"                 },
-       { do_bad,               SIGILL,  BUS_ADRALN,    "alignment exception"              },
+       { do_bad,               SIGBUS,  BUS_ADRALN,    "alignment exception"              },
        { do_bad,               SIGKILL, 0,             "terminal exception"               },
-       { do_bad,               SIGILL,  BUS_ADRALN,    "alignment exception"              },
-/* Do we need runtime check ? */
-#if __LINUX_ARM_ARCH__ < 6
+       { do_bad,               SIGBUS,  BUS_ADRALN,    "alignment exception"              },
        { do_bad,               SIGBUS,  0,             "external abort on linefetch"      },
-#else
-       { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "I-cache maintenance fault"        },
-#endif
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "section translation fault"        },
        { do_bad,               SIGBUS,  0,             "external abort on linefetch"      },
        { do_page_fault,        SIGSEGV, SEGV_MAPERR,   "page translation fault"           },
@@ -508,13 +512,15 @@ static struct fsr_info {
 
 void __init
 hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
-               int sig, const char *name)
+               int sig, int code, const char *name)
 {
-       if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) {
-               fsr_info[nr].fn   = fn;
-               fsr_info[nr].sig  = sig;
-               fsr_info[nr].name = name;
-       }
+       if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))
+               BUG();
+
+       fsr_info[nr].fn   = fn;
+       fsr_info[nr].sig  = sig;
+       fsr_info[nr].code = code;
+       fsr_info[nr].name = name;
 }
 
 /*
@@ -594,3 +600,25 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
        arm_notify_die("", regs, &info, ifsr, 0);
 }
 
+static int __init exceptions_init(void)
+{
+       if (cpu_architecture() >= CPU_ARCH_ARMv6) {
+               hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR,
+                               "I-cache maintenance fault");
+       }
+
+       if (cpu_architecture() >= CPU_ARCH_ARMv7) {
+               /*
+                * TODO: Access flag faults introduced in ARMv6K.
+                * Runtime check for 'K' extension is needed
+                */
+               hook_fault_code(3, do_bad, SIGSEGV, SEGV_MAPERR,
+                               "section access flag fault");
+               hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR,
+                               "section access flag fault");
+       }
+
+       return 0;
+}
+
+arch_initcall(exceptions_init);
index 086816b205b8cf25c9d178c9d56c44a654e2ff9f..6ab244062b4ab2f720e84d870011faac64878c81 100644 (file)
@@ -163,19 +163,22 @@ static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth);
 
 void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
 {
-       unsigned int idx, cpu = smp_processor_id();
-       int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
+       unsigned int idx, cpu;
+       int *depth;
        unsigned long vaddr, flags;
        pte_t pte, *ptep;
 
+       if (!in_interrupt())
+               preempt_disable();
+
+       cpu = smp_processor_id();
+       depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
+
        idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        ptep = TOP_PTE(vaddr);
        pte = mk_pte(page, kmap_prot);
 
-       if (!in_interrupt())
-               preempt_disable();
-
        raw_local_irq_save(flags);
        (*depth)++;
        if (pte_val(*ptep) == pte_val(pte)) {
index f6a9994653237ddc2a56c7c1fbd9070615cea937..7185b00650fe419d0fa0f43b3e79e2e0d90cf6e6 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/initrd.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/memblock.h>
 
 #include <asm/mach-types.h>
 #include <asm/sections.h>
@@ -79,38 +80,37 @@ struct meminfo meminfo;
 void show_mem(void)
 {
        int free = 0, total = 0, reserved = 0;
-       int shared = 0, cached = 0, slab = 0, node, i;
+       int shared = 0, cached = 0, slab = 0, i;
        struct meminfo * mi = &meminfo;
 
        printk("Mem-info:\n");
        show_free_areas();
-       for_each_online_node(node) {
-               for_each_nodebank (i,mi,node) {
-                       struct membank *bank = &mi->bank[i];
-                       unsigned int pfn1, pfn2;
-                       struct page *page, *end;
-
-                       pfn1 = bank_pfn_start(bank);
-                       pfn2 = bank_pfn_end(bank);
-
-                       page = pfn_to_page(pfn1);
-                       end  = pfn_to_page(pfn2 - 1) + 1;
-
-                       do {
-                               total++;
-                               if (PageReserved(page))
-                                       reserved++;
-                               else if (PageSwapCache(page))
-                                       cached++;
-                               else if (PageSlab(page))
-                                       slab++;
-                               else if (!page_count(page))
-                                       free++;
-                               else
-                                       shared += page_count(page) - 1;
-                               page++;
-                       } while (page < end);
-               }
+
+       for_each_bank (i, mi) {
+               struct membank *bank = &mi->bank[i];
+               unsigned int pfn1, pfn2;
+               struct page *page, *end;
+
+               pfn1 = bank_pfn_start(bank);
+               pfn2 = bank_pfn_end(bank);
+
+               page = pfn_to_page(pfn1);
+               end  = pfn_to_page(pfn2 - 1) + 1;
+
+               do {
+                       total++;
+                       if (PageReserved(page))
+                               reserved++;
+                       else if (PageSwapCache(page))
+                               cached++;
+                       else if (PageSlab(page))
+                               slab++;
+                       else if (!page_count(page))
+                               free++;
+                       else
+                               shared += page_count(page) - 1;
+                       page++;
+               } while (page < end);
        }
 
        printk("%d pages of RAM\n", total);
@@ -121,7 +121,7 @@ void show_mem(void)
        printk("%d pages swap cached\n", cached);
 }
 
-static void __init find_node_limits(int node, struct meminfo *mi,
+static void __init find_limits(struct meminfo *mi,
        unsigned long *min, unsigned long *max_low, unsigned long *max_high)
 {
        int i;
@@ -129,7 +129,7 @@ static void __init find_node_limits(int node, struct meminfo *mi,
        *min = -1UL;
        *max_low = *max_high = 0;
 
-       for_each_nodebank(i, mi, node) {
+       for_each_bank (i, mi) {
                struct membank *bank = &mi->bank[i];
                unsigned long start, end;
 
@@ -147,155 +147,64 @@ static void __init find_node_limits(int node, struct meminfo *mi,
        }
 }
 
-/*
- * FIXME: We really want to avoid allocating the bootmap bitmap
- * over the top of the initrd.  Hopefully, this is located towards
- * the start of a bank, so if we allocate the bootmap bitmap at
- * the end, we won't clash.
- */
-static unsigned int __init
-find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
-{
-       unsigned int start_pfn, i, bootmap_pfn;
-
-       start_pfn   = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT;
-       bootmap_pfn = 0;
-
-       for_each_nodebank(i, mi, node) {
-               struct membank *bank = &mi->bank[i];
-               unsigned int start, end;
-
-               start = bank_pfn_start(bank);
-               end   = bank_pfn_end(bank);
-
-               if (end < start_pfn)
-                       continue;
-
-               if (start < start_pfn)
-                       start = start_pfn;
-
-               if (end <= start)
-                       continue;
-
-               if (end - start >= bootmap_pages) {
-                       bootmap_pfn = start;
-                       break;
-               }
-       }
-
-       if (bootmap_pfn == 0)
-               BUG();
-
-       return bootmap_pfn;
-}
-
-static int __init check_initrd(struct meminfo *mi)
-{
-       int initrd_node = -2;
-#ifdef CONFIG_BLK_DEV_INITRD
-       unsigned long end = phys_initrd_start + phys_initrd_size;
-
-       /*
-        * Make sure that the initrd is within a valid area of
-        * memory.
-        */
-       if (phys_initrd_size) {
-               unsigned int i;
-
-               initrd_node = -1;
-
-               for (i = 0; i < mi->nr_banks; i++) {
-                       struct membank *bank = &mi->bank[i];
-                       if (bank_phys_start(bank) <= phys_initrd_start &&
-                           end <= bank_phys_end(bank))
-                               initrd_node = bank->node;
-               }
-       }
-
-       if (initrd_node == -1) {
-               printk(KERN_ERR "INITRD: 0x%08lx+0x%08lx extends beyond "
-                      "physical memory - disabling initrd\n",
-                      phys_initrd_start, phys_initrd_size);
-               phys_initrd_start = phys_initrd_size = 0;
-       }
-#endif
-
-       return initrd_node;
-}
-
-static void __init bootmem_init_node(int node, struct meminfo *mi,
+static void __init arm_bootmem_init(struct meminfo *mi,
        unsigned long start_pfn, unsigned long end_pfn)
 {
-       unsigned long boot_pfn;
        unsigned int boot_pages;
+       phys_addr_t bitmap;
        pg_data_t *pgdat;
        int i;
 
        /*
-        * Allocate the bootmem bitmap page.
+        * Allocate the bootmem bitmap page.  This must be in a region
+        * of memory which has already been mapped.
         */
        boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
-       boot_pfn = find_bootmap_pfn(node, mi, boot_pages);
+       bitmap = memblock_alloc_base(boot_pages << PAGE_SHIFT, L1_CACHE_BYTES,
+                               __pfn_to_phys(end_pfn));
 
        /*
-        * Initialise the bootmem allocator for this node, handing the
+        * Initialise the bootmem allocator, handing the
         * memory banks over to bootmem.
         */
-       node_set_online(node);
-       pgdat = NODE_DATA(node);
-       init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn);
+       node_set_online(0);
+       pgdat = NODE_DATA(0);
+       init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn);
 
-       for_each_nodebank(i, mi, node) {
+       for_each_bank(i, mi) {
                struct membank *bank = &mi->bank[i];
                if (!bank->highmem)
-                       free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank));
+                       free_bootmem(bank_phys_start(bank), bank_phys_size(bank));
        }
 
        /*
-        * Reserve the bootmem bitmap for this node.
+        * Reserve the memblock reserved regions in bootmem.
         */
-       reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT,
-                            boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
-}
-
-static void __init bootmem_reserve_initrd(int node)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-       pg_data_t *pgdat = NODE_DATA(node);
-       int res;
-
-       res = reserve_bootmem_node(pgdat, phys_initrd_start,
-                            phys_initrd_size, BOOTMEM_EXCLUSIVE);
-
-       if (res == 0) {
-               initrd_start = __phys_to_virt(phys_initrd_start);
-               initrd_end = initrd_start + phys_initrd_size;
-       } else {
-               printk(KERN_ERR
-                       "INITRD: 0x%08lx+0x%08lx overlaps in-use "
-                       "memory region - disabling initrd\n",
-                       phys_initrd_start, phys_initrd_size);
+       for (i = 0; i < memblock.reserved.cnt; i++) {
+               phys_addr_t start = memblock_start_pfn(&memblock.reserved, i);
+               if (start >= start_pfn &&
+                   memblock_end_pfn(&memblock.reserved, i) <= end_pfn)
+                       reserve_bootmem_node(pgdat, __pfn_to_phys(start),
+                               memblock_size_bytes(&memblock.reserved, i),
+                               BOOTMEM_DEFAULT);
        }
-#endif
 }
 
-static void __init bootmem_free_node(int node, struct meminfo *mi)
+static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min,
+       unsigned long max_low, unsigned long max_high)
 {
        unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
-       unsigned long min, max_low, max_high;
        int i;
 
-       find_node_limits(node, mi, &min, &max_low, &max_high);
-
        /*
-        * initialise the zones within this node.
+        * initialise the zones.
         */
        memset(zone_size, 0, sizeof(zone_size));
 
        /*
-        * The size of this node has already been determined.  If we need
-        * to do anything fancy with the allocation of this memory to the
-        * zones, now is the time to do it.
+        * The memory size has already been determined.  If we need
+        * to do anything fancy with the allocation of this memory
+        * to the zones, now is the time to do it.
         */
        zone_size[0] = max_low - min;
 #ifdef CONFIG_HIGHMEM
@@ -303,11 +212,11 @@ static void __init bootmem_free_node(int node, struct meminfo *mi)
 #endif
 
        /*
-        * For each bank in this node, calculate the size of the holes.
-        *  holes = node_size - sum(bank_sizes_in_node)
+        * Calculate the size of the holes.
+        *  holes = node_size - sum(bank_sizes)
         */
        memcpy(zhole_size, zone_size, sizeof(zhole_size));
-       for_each_nodebank(i, mi, node) {
+       for_each_bank(i, mi) {
                int idx = 0;
 #ifdef CONFIG_HIGHMEM
                if (mi->bank[i].highmem)
@@ -320,24 +229,23 @@ static void __init bootmem_free_node(int node, struct meminfo *mi)
         * Adjust the sizes according to any special requirements for
         * this machine type.
         */
-       arch_adjust_zones(node, zone_size, zhole_size);
+       arch_adjust_zones(zone_size, zhole_size);
 
-       free_area_init_node(node, zone_size, min, zhole_size);
+       free_area_init_node(0, zone_size, min, zhole_size);
 }
 
 #ifndef CONFIG_SPARSEMEM
 int pfn_valid(unsigned long pfn)
 {
-       struct meminfo *mi = &meminfo;
-       unsigned int left = 0, right = mi->nr_banks;
+       struct memblock_region *mem = &memblock.memory;
+       unsigned int left = 0, right = mem->cnt;
 
        do {
                unsigned int mid = (right + left) / 2;
-               struct membank *bank = &mi->bank[mid];
 
-               if (pfn < bank_pfn_start(bank))
+               if (pfn < memblock_start_pfn(mem, mid))
                        right = mid;
-               else if (pfn >= bank_pfn_end(bank))
+               else if (pfn >= memblock_end_pfn(mem, mid))
                        left = mid + 1;
                else
                        return 1;
@@ -346,73 +254,69 @@ int pfn_valid(unsigned long pfn)
 }
 EXPORT_SYMBOL(pfn_valid);
 
-static void arm_memory_present(struct meminfo *mi, int node)
+static void arm_memory_present(void)
 {
 }
 #else
-static void arm_memory_present(struct meminfo *mi, int node)
+static void arm_memory_present(void)
 {
        int i;
-       for_each_nodebank(i, mi, node) {
-               struct membank *bank = &mi->bank[i];
-               memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank));
-       }
+       for (i = 0; i < memblock.memory.cnt; i++)
+               memory_present(0, memblock_start_pfn(&memblock.memory, i),
+                                 memblock_end_pfn(&memblock.memory, i));
 }
 #endif
 
-void __init bootmem_init(void)
+void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 {
-       struct meminfo *mi = &meminfo;
-       unsigned long min, max_low, max_high;
-       int node, initrd_node;
+       int i;
 
-       /*
-        * Locate which node contains the ramdisk image, if any.
-        */
-       initrd_node = check_initrd(mi);
+       memblock_init();
+       for (i = 0; i < mi->nr_banks; i++)
+               memblock_add(mi->bank[i].start, mi->bank[i].size);
 
-       max_low = max_high = 0;
+       /* Register the kernel text, kernel data and initrd with memblock. */
+#ifdef CONFIG_XIP_KERNEL
+       memblock_reserve(__pa(_data), _end - _data);
+#else
+       memblock_reserve(__pa(_stext), _end - _stext);
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (phys_initrd_size) {
+               memblock_reserve(phys_initrd_start, phys_initrd_size);
 
-       /*
-        * Run through each node initialising the bootmem allocator.
-        */
-       for_each_node(node) {
-               unsigned long node_low, node_high;
+               /* Now convert initrd to virtual addresses */
+               initrd_start = __phys_to_virt(phys_initrd_start);
+               initrd_end = initrd_start + phys_initrd_size;
+       }
+#endif
 
-               find_node_limits(node, mi, &min, &node_low, &node_high);
+       arm_mm_memblock_reserve();
 
-               if (node_low > max_low)
-                       max_low = node_low;
-               if (node_high > max_high)
-                       max_high = node_high;
+       /* reserve any platform specific memblock areas */
+       if (mdesc->reserve)
+               mdesc->reserve();
 
-               /*
-                * If there is no memory in this node, ignore it.
-                * (We can't have nodes which have no lowmem)
-                */
-               if (node_low == 0)
-                       continue;
+       memblock_analyze();
+       memblock_dump_all();
+}
 
-               bootmem_init_node(node, mi, min, node_low);
+void __init bootmem_init(void)
+{
+       struct meminfo *mi = &meminfo;
+       unsigned long min, max_low, max_high;
 
-               /*
-                * Reserve any special node zero regions.
-                */
-               if (node == 0)
-                       reserve_node_zero(NODE_DATA(node));
+       max_low = max_high = 0;
 
-               /*
-                * If the initrd is in this node, reserve its memory.
-                */
-               if (node == initrd_node)
-                       bootmem_reserve_initrd(node);
+       find_limits(mi, &min, &max_low, &max_high);
 
-               /*
-                * Sparsemem tries to allocate bootmem in memory_present(),
-                * so must be done after the fixed reservations
-                */
-               arm_memory_present(mi, node);
-       }
+       arm_bootmem_init(mi, min, max_low);
+
+       /*
+        * Sparsemem tries to allocate bootmem in memory_present(),
+        * so must be done after the fixed reservations
+        */
+       arm_memory_present();
 
        /*
         * sparse_init() needs the bootmem allocator up and running.
@@ -420,12 +324,11 @@ void __init bootmem_init(void)
        sparse_init();
 
        /*
-        * Now free memory in each node - free_area_init_node needs
+        * Now free the memory - free_area_init_node needs
         * the sparse mem_map arrays initialized by sparse_init()
         * for memmap_init_zone(), otherwise all PFNs are invalid.
         */
-       for_each_node(node)
-               bootmem_free_node(node, mi);
+       arm_bootmem_free(mi, min, max_low, max_high);
 
        high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1;
 
@@ -460,7 +363,7 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s)
 }
 
 static inline void
-free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
+free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 {
        struct page *start_pg, *end_pg;
        unsigned long pg, pgend;
@@ -483,40 +386,39 @@ free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
         * free the section of the memmap array.
         */
        if (pg < pgend)
-               free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
+               free_bootmem(pg, pgend - pg);
 }
 
 /*
  * The mem_map array can get very big.  Free the unused area of the memory map.
  */
-static void __init free_unused_memmap_node(int node, struct meminfo *mi)
+static void __init free_unused_memmap(struct meminfo *mi)
 {
        unsigned long bank_start, prev_bank_end = 0;
        unsigned int i;
 
        /*
-        * [FIXME] This relies on each bank being in address order.  This
-        * may not be the case, especially if the user has provided the
-        * information on the command line.
+        * This relies on each bank being in address order.
+        * The banks are sorted previously in bootmem_init().
         */
-       for_each_nodebank(i, mi, node) {
+       for_each_bank(i, mi) {
                struct membank *bank = &mi->bank[i];
 
                bank_start = bank_pfn_start(bank);
-               if (bank_start < prev_bank_end) {
-                       printk(KERN_ERR "MEM: unordered memory banks.  "
-                               "Not freeing memmap.\n");
-                       break;
-               }
 
                /*
                 * If we had a previous bank, and there is a space
                 * between the current bank and the previous, free it.
                 */
-               if (prev_bank_end && prev_bank_end != bank_start)
-                       free_memmap(node, prev_bank_end, bank_start);
+               if (prev_bank_end && prev_bank_end < bank_start)
+                       free_memmap(prev_bank_end, bank_start);
 
-               prev_bank_end = bank_pfn_end(bank);
+               /*
+                * Align up here since the VM subsystem insists that the
+                * memmap entries are valid from the bank end aligned to
+                * MAX_ORDER_NR_PAGES.
+                */
+               prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
        }
 }
 
@@ -528,21 +430,19 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)
 void __init mem_init(void)
 {
        unsigned long reserved_pages, free_pages;
-       int i, node;
+       int i;
+#ifdef CONFIG_HAVE_TCM
+       /* These pointers are filled in on TCM detection */
+       extern u32 dtcm_end;
+       extern u32 itcm_end;
+#endif
 
-#ifndef CONFIG_DISCONTIGMEM
        max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
-#endif
 
        /* this will put all unused low memory onto the freelists */
-       for_each_online_node(node) {
-               pg_data_t *pgdat = NODE_DATA(node);
+       free_unused_memmap(&meminfo);
 
-               free_unused_memmap_node(node, &meminfo);
-
-               if (pgdat->node_spanned_pages != 0)
-                       totalram_pages += free_all_bootmem_node(pgdat);
-       }
+       totalram_pages += free_all_bootmem();
 
 #ifdef CONFIG_SA1111
        /* now that our DMA memory is actually so designated, we can free it */
@@ -552,39 +452,35 @@ void __init mem_init(void)
 
 #ifdef CONFIG_HIGHMEM
        /* set highmem page free */
-       for_each_online_node(node) {
-               for_each_nodebank (i, &meminfo, node) {
-                       unsigned long start = bank_pfn_start(&meminfo.bank[i]);
-                       unsigned long end = bank_pfn_end(&meminfo.bank[i]);
-                       if (start >= max_low_pfn + PHYS_PFN_OFFSET)
-                               totalhigh_pages += free_area(start, end, NULL);
-               }
+       for_each_bank (i, &meminfo) {
+               unsigned long start = bank_pfn_start(&meminfo.bank[i]);
+               unsigned long end = bank_pfn_end(&meminfo.bank[i]);
+               if (start >= max_low_pfn + PHYS_PFN_OFFSET)
+                       totalhigh_pages += free_area(start, end, NULL);
        }
        totalram_pages += totalhigh_pages;
 #endif
 
        reserved_pages = free_pages = 0;
 
-       for_each_online_node(node) {
-               for_each_nodebank(i, &meminfo, node) {
-                       struct membank *bank = &meminfo.bank[i];
-                       unsigned int pfn1, pfn2;
-                       struct page *page, *end;
-
-                       pfn1 = bank_pfn_start(bank);
-                       pfn2 = bank_pfn_end(bank);
-
-                       page = pfn_to_page(pfn1);
-                       end  = pfn_to_page(pfn2 - 1) + 1;
-
-                       do {
-                               if (PageReserved(page))
-                                       reserved_pages++;
-                               else if (!page_count(page))
-                                       free_pages++;
-                               page++;
-                       } while (page < end);
-               }
+       for_each_bank(i, &meminfo) {
+               struct membank *bank = &meminfo.bank[i];
+               unsigned int pfn1, pfn2;
+               struct page *page, *end;
+
+               pfn1 = bank_pfn_start(bank);
+               pfn2 = bank_pfn_end(bank);
+
+               page = pfn_to_page(pfn1);
+               end  = pfn_to_page(pfn2 - 1) + 1;
+
+               do {
+                       if (PageReserved(page))
+                               reserved_pages++;
+                       else if (!page_count(page))
+                               free_pages++;
+                       page++;
+               } while (page < end);
        }
 
        /*
@@ -611,6 +507,10 @@ void __init mem_init(void)
 
        printk(KERN_NOTICE "Virtual kernel memory layout:\n"
                        "    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+#ifdef CONFIG_HAVE_TCM
+                       "    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+                       "    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+#endif
                        "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_MMU
                        "    DMA     : 0x%08lx - 0x%08lx   (%4ld MB)\n"
@@ -627,6 +527,10 @@ void __init mem_init(void)
 
                        MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
                                (PAGE_SIZE)),
+#ifdef CONFIG_HAVE_TCM
+                       MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
+                       MLK(ITCM_OFFSET, (unsigned long) itcm_end),
+#endif
                        MLK(FIXADDR_START, FIXADDR_TOP),
 #ifdef CONFIG_MMU
                        MLM(CONSISTENT_BASE, CONSISTENT_END),
index 28c8b950ef04e84f6d0893712fb22c5394808ee6..ab506272b2d3ef459b264b7741d61af46f6aa6b8 100644 (file)
  */
 #define VM_ARM_SECTION_MAPPING 0x80000000
 
-static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
-                         unsigned long phys_addr, const struct mem_type *type)
-{
-       pgprot_t prot = __pgprot(type->prot_pte);
-       pte_t *pte;
-
-       pte = pte_alloc_kernel(pmd, addr);
-       if (!pte)
-               return -ENOMEM;
-
-       do {
-               if (!pte_none(*pte))
-                       goto bad;
-
-               set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0);
-               phys_addr += PAGE_SIZE;
-       } while (pte++, addr += PAGE_SIZE, addr != end);
-       return 0;
-
- bad:
-       printk(KERN_CRIT "remap_area_pte: page already exists\n");
-       BUG();
-}
-
-static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr,
-                                unsigned long end, unsigned long phys_addr,
-                                const struct mem_type *type)
-{
-       unsigned long next;
-       pmd_t *pmd;
-       int ret = 0;
-
-       pmd = pmd_alloc(&init_mm, pgd, addr);
-       if (!pmd)
-               return -ENOMEM;
-
-       do {
-               next = pmd_addr_end(addr, end);
-               ret = remap_area_pte(pmd, addr, next, phys_addr, type);
-               if (ret)
-                       return ret;
-               phys_addr += next - addr;
-       } while (pmd++, addr = next, addr != end);
-       return ret;
-}
-
-static int remap_area_pages(unsigned long start, unsigned long pfn,
-                           size_t size, const struct mem_type *type)
-{
-       unsigned long addr = start;
-       unsigned long next, end = start + size;
-       unsigned long phys_addr = __pfn_to_phys(pfn);
-       pgd_t *pgd;
-       int err = 0;
-
-       BUG_ON(addr >= end);
-       pgd = pgd_offset_k(addr);
-       do {
-               next = pgd_addr_end(addr, end);
-               err = remap_area_pmd(pgd, addr, next, phys_addr, type);
-               if (err)
-                       break;
-               phys_addr += next - addr;
-       } while (pgd++, addr = next, addr != end);
-
-       return err;
-}
-
 int ioremap_page(unsigned long virt, unsigned long phys,
                 const struct mem_type *mtype)
 {
-       return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, mtype);
+       return ioremap_page_range(virt, virt + PAGE_SIZE, phys,
+                                 __pgprot(mtype->prot_pte));
 }
 EXPORT_SYMBOL(ioremap_page);
 
@@ -268,6 +201,12 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
        if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
                return NULL;
 
+       /*
+        * Don't allow RAM to be mapped - this causes problems with ARMv6+
+        */
+       if (WARN_ON(pfn_valid(pfn)))
+               return NULL;
+
        type = get_mem_type(mtype);
        if (!type)
                return NULL;
@@ -294,7 +233,8 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
                err = remap_area_sections(addr, pfn, size, type);
        } else
 #endif
-               err = remap_area_pages(addr, pfn, size, type);
+               err = ioremap_page_range(addr, addr + size, __pfn_to_phys(pfn),
+                                        __pgprot(type->prot_pte));
 
        if (err) {
                vunmap((void *)addr);
index 815d08eecbb0f69a15a46f6990c481fd49dae779..6630620380a4aa0f538aed006a2de6f04c71d3dd 100644 (file)
@@ -28,7 +28,5 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
 
 #endif
 
-struct pglist_data;
-
 void __init bootmem_init(void);
-void reserve_node_zero(struct pglist_data *pgdat);
+void arm_mm_memblock_reserve(void);
index f5abc51c5a07ff24e047ef333c7dd47b942fc3a4..4f5b39687df541a417d4c3a9ac888fc53a31b999 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/shm.h>
 #include <linux/sched.h>
 #include <linux/io.h>
+#include <linux/random.h>
 #include <asm/cputype.h>
 #include <asm/system.h>
 
@@ -80,6 +81,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
                start_addr = addr = TASK_UNMAPPED_BASE;
                mm->cached_hole_size = 0;
        }
+       /* 8 bits of randomness in 20 address space bits */
+       if (current->flags & PF_RANDOMIZE)
+               addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
 
 full_search:
        if (do_align)
index 28589417118643aec349aff677e3c1e0be53efa3..6e1c4f6a2b3f3a09ed3f10be9aeafab36c9a0924 100644 (file)
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
 #include <linux/mman.h>
 #include <linux/nodemask.h>
+#include <linux/memblock.h>
 #include <linux/sort.h>
 
 #include <asm/cputype.h>
-#include <asm/mach-types.h>
 #include <asm/sections.h>
 #include <asm/cachetype.h>
 #include <asm/setup.h>
@@ -258,6 +257,19 @@ static struct mem_type mem_types[] = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
                .domain    = DOMAIN_KERNEL,
        },
+       [MT_MEMORY_DTCM] = {
+               .prot_pte       = L_PTE_PRESENT | L_PTE_YOUNG |
+                                 L_PTE_DIRTY | L_PTE_WRITE,
+               .prot_l1        = PMD_TYPE_TABLE,
+               .prot_sect      = PMD_TYPE_SECT | PMD_SECT_XN,
+               .domain         = DOMAIN_KERNEL,
+       },
+       [MT_MEMORY_ITCM] = {
+               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+                               L_PTE_USER | L_PTE_EXEC,
+               .prot_l1   = PMD_TYPE_TABLE,
+               .domain    = DOMAIN_IO,
+       },
 };
 
 const struct mem_type *get_mem_type(unsigned int type)
@@ -488,18 +500,28 @@ static void __init build_mem_type_table(void)
 
 #define vectors_base() (vectors_high() ? 0xffff0000 : 0)
 
-static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
-                                 unsigned long end, unsigned long pfn,
-                                 const struct mem_type *type)
+static void __init *early_alloc(unsigned long sz)
 {
-       pte_t *pte;
+       void *ptr = __va(memblock_alloc(sz, sz));
+       memset(ptr, 0, sz);
+       return ptr;
+}
 
+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
+{
        if (pmd_none(*pmd)) {
-               pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
-               __pmd_populate(pmd, __pa(pte) | type->prot_l1);
+               pte_t *pte = early_alloc(2 * PTRS_PER_PTE * sizeof(pte_t));
+               __pmd_populate(pmd, __pa(pte) | prot);
        }
+       BUG_ON(pmd_bad(*pmd));
+       return pte_offset_kernel(pmd, addr);
+}
 
-       pte = pte_offset_kernel(pmd, addr);
+static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
+                                 unsigned long end, unsigned long pfn,
+                                 const struct mem_type *type)
+{
+       pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
        do {
                set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
                pfn++;
@@ -668,7 +690,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
                create_mapping(io_desc + i);
 }
 
-static unsigned long __initdata vmalloc_reserve = SZ_128M;
+static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M);
 
 /*
  * vmalloc=size forces the vmalloc area to be exactly 'size'
@@ -677,7 +699,7 @@ static unsigned long __initdata vmalloc_reserve = SZ_128M;
  */
 static int __init early_vmalloc(char *arg)
 {
-       vmalloc_reserve = memparse(arg, NULL);
+       unsigned long vmalloc_reserve = memparse(arg, NULL);
 
        if (vmalloc_reserve < SZ_16M) {
                vmalloc_reserve = SZ_16M;
@@ -692,22 +714,26 @@ static int __init early_vmalloc(char *arg)
                        "vmalloc area is too big, limiting to %luMB\n",
                        vmalloc_reserve >> 20);
        }
+
+       vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve);
        return 0;
 }
 early_param("vmalloc", early_vmalloc);
 
-#define VMALLOC_MIN    (void *)(VMALLOC_END - vmalloc_reserve)
+phys_addr_t lowmem_end_addr;
 
 static void __init sanity_check_meminfo(void)
 {
        int i, j, highmem = 0;
 
+       lowmem_end_addr = __pa(vmalloc_min - 1) + 1;
+
        for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
                struct membank *bank = &meminfo.bank[j];
                *bank = meminfo.bank[i];
 
 #ifdef CONFIG_HIGHMEM
-               if (__va(bank->start) > VMALLOC_MIN ||
+               if (__va(bank->start) > vmalloc_min ||
                    __va(bank->start) < (void *)PAGE_OFFSET)
                        highmem = 1;
 
@@ -717,8 +743,8 @@ static void __init sanity_check_meminfo(void)
                 * Split those memory banks which are partially overlapping
                 * the vmalloc area greatly simplifying things later.
                 */
-               if (__va(bank->start) < VMALLOC_MIN &&
-                   bank->size > VMALLOC_MIN - __va(bank->start)) {
+               if (__va(bank->start) < vmalloc_min &&
+                   bank->size > vmalloc_min - __va(bank->start)) {
                        if (meminfo.nr_banks >= NR_BANKS) {
                                printk(KERN_CRIT "NR_BANKS too low, "
                                                 "ignoring high memory\n");
@@ -727,12 +753,12 @@ static void __init sanity_check_meminfo(void)
                                        (meminfo.nr_banks - i) * sizeof(*bank));
                                meminfo.nr_banks++;
                                i++;
-                               bank[1].size -= VMALLOC_MIN - __va(bank->start);
-                               bank[1].start = __pa(VMALLOC_MIN - 1) + 1;
+                               bank[1].size -= vmalloc_min - __va(bank->start);
+                               bank[1].start = __pa(vmalloc_min - 1) + 1;
                                bank[1].highmem = highmem = 1;
                                j++;
                        }
-                       bank->size = VMALLOC_MIN - __va(bank->start);
+                       bank->size = vmalloc_min - __va(bank->start);
                }
 #else
                bank->highmem = highmem;
@@ -741,7 +767,7 @@ static void __init sanity_check_meminfo(void)
                 * Check whether this memory bank would entirely overlap
                 * the vmalloc area.
                 */
-               if (__va(bank->start) >= VMALLOC_MIN ||
+               if (__va(bank->start) >= vmalloc_min ||
                    __va(bank->start) < (void *)PAGE_OFFSET) {
                        printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
                               "(vmalloc region overlap).\n",
@@ -753,9 +779,9 @@ static void __init sanity_check_meminfo(void)
                 * Check whether this memory bank would partially overlap
                 * the vmalloc area.
                 */
-               if (__va(bank->start + bank->size) > VMALLOC_MIN ||
+               if (__va(bank->start + bank->size) > vmalloc_min ||
                    __va(bank->start + bank->size) < __va(bank->start)) {
-                       unsigned long newsize = VMALLOC_MIN - __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,
@@ -827,101 +853,23 @@ static inline void prepare_page_table(void)
 }
 
 /*
- * Reserve the various regions of node 0
+ * Reserve the special regions of memory
  */
-void __init reserve_node_zero(pg_data_t *pgdat)
+void __init arm_mm_memblock_reserve(void)
 {
-       unsigned long res_size = 0;
-
-       /*
-        * Register the kernel text and data with bootmem.
-        * Note that this can only be in node 0.
-        */
-#ifdef CONFIG_XIP_KERNEL
-       reserve_bootmem_node(pgdat, __pa(_data), _end - _data,
-                       BOOTMEM_DEFAULT);
-#else
-       reserve_bootmem_node(pgdat, __pa(_stext), _end - _stext,
-                       BOOTMEM_DEFAULT);
-#endif
-
        /*
         * Reserve the page tables.  These are already in use,
         * and can only be in node 0.
         */
-       reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
-                            PTRS_PER_PGD * sizeof(pgd_t), BOOTMEM_DEFAULT);
-
-       /*
-        * Hmm... This should go elsewhere, but we really really need to
-        * stop things allocating the low memory; ideally we need a better
-        * implementation of GFP_DMA which does not assume that DMA-able
-        * memory starts at zero.
-        */
-       if (machine_is_integrator() || machine_is_cintegrator())
-               res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
-
-       /*
-        * These should likewise go elsewhere.  They pre-reserve the
-        * screen memory region at the start of main system memory.
-        */
-       if (machine_is_edb7211())
-               res_size = 0x00020000;
-       if (machine_is_p720t())
-               res_size = 0x00014000;
-
-       /* H1940, RX3715 and RX1950 need to reserve this for suspend */
-
-       if (machine_is_h1940() || machine_is_rx3715()
-               || machine_is_rx1950()) {
-               reserve_bootmem_node(pgdat, 0x30003000, 0x1000,
-                               BOOTMEM_DEFAULT);
-               reserve_bootmem_node(pgdat, 0x30081000, 0x1000,
-                               BOOTMEM_DEFAULT);
-       }
-
-       if (machine_is_palmld() || machine_is_palmtx()) {
-               reserve_bootmem_node(pgdat, 0xa0000000, 0x1000,
-                               BOOTMEM_EXCLUSIVE);
-               reserve_bootmem_node(pgdat, 0xa0200000, 0x1000,
-                               BOOTMEM_EXCLUSIVE);
-       }
-
-       if (machine_is_treo680() || machine_is_centro()) {
-               reserve_bootmem_node(pgdat, 0xa0000000, 0x1000,
-                               BOOTMEM_EXCLUSIVE);
-               reserve_bootmem_node(pgdat, 0xa2000000, 0x1000,
-                               BOOTMEM_EXCLUSIVE);
-       }
-
-       if (machine_is_palmt5())
-               reserve_bootmem_node(pgdat, 0xa0200000, 0x1000,
-                               BOOTMEM_EXCLUSIVE);
-
-       /*
-        * U300 - This platform family can share physical memory
-        * between two ARM cpus, one running Linux and the other
-        * running another OS.
-        */
-       if (machine_is_u300()) {
-#ifdef CONFIG_MACH_U300_SINGLE_RAM
-#if ((CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1) == 1) &&   \
-       CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
-               res_size = 0x00100000;
-#endif
-#endif
-       }
+       memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t));
 
 #ifdef CONFIG_SA1111
        /*
         * Because of the SA1111 DMA bug, we want to preserve our
         * precious DMA-able memory...
         */
-       res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
+       memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
 #endif
-       if (res_size)
-               reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size,
-                               BOOTMEM_DEFAULT);
 }
 
 /*
@@ -940,7 +888,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
        /*
         * Allocate the vector page early.
         */
-       vectors = alloc_bootmem_low_pages(PAGE_SIZE);
+       vectors = early_alloc(PAGE_SIZE);
 
        for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
                pmd_clear(pmd_off_k(addr));
@@ -1011,11 +959,8 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
 static void __init kmap_init(void)
 {
 #ifdef CONFIG_HIGHMEM
-       pmd_t *pmd = pmd_off_k(PKMAP_BASE);
-       pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
-       BUG_ON(!pmd_none(*pmd) || !pte);
-       __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE);
-       pkmap_page_table = pte + PTRS_PER_PTE;
+       pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
+               PKMAP_BASE, _PAGE_KERNEL_TABLE);
 #endif
 }
 
@@ -1066,17 +1011,16 @@ void __init paging_init(struct machine_desc *mdesc)
        sanity_check_meminfo();
        prepare_page_table();
        map_lowmem();
-       bootmem_init();
        devicemaps_init(mdesc);
        kmap_init();
 
        top_pmd = pmd_off_k(0xffff0000);
 
-       /*
-        * allocate the zero page.  Note that this always succeeds and
-        * returns a zeroed result.
-        */
-       zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
+       /* allocate the zero page. */
+       zero_page = early_alloc(PAGE_SIZE);
+
+       bootmem_init();
+
        empty_zero_page = virt_to_page(zero_page);
        __flush_dcache_page(NULL, empty_zero_page);
 }
index 33b327379f0756e14eff3d9f0cd23a2f022eb112..687d02319a41ea68afcfe65698204a4db84d8400 100644 (file)
@@ -6,8 +6,8 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
-#include <linux/bootmem.h>
 #include <linux/io.h>
+#include <linux/memblock.h>
 
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
 
 #include "mm.h"
 
-/*
- * Reserve the various regions of node 0
- */
-void __init reserve_node_zero(pg_data_t *pgdat)
+void __init arm_mm_memblock_reserve(void)
 {
-       /*
-        * Register the kernel text and data with bootmem.
-        * Note that this can only be in node 0.
-        */
-#ifdef CONFIG_XIP_KERNEL
-       reserve_bootmem_node(pgdat, __pa(_data), _end - _data,
-                       BOOTMEM_DEFAULT);
-#else
-       reserve_bootmem_node(pgdat, __pa(_stext), _end - _stext,
-                       BOOTMEM_DEFAULT);
-#endif
-
        /*
         * Register the exception vector page.
         * some architectures which the DRAM is the exception vector to trap,
         * alloc_page breaks with error, although it is not NULL, but "0."
         */
-       reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE,
-                       BOOTMEM_DEFAULT);
+       memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE);
 }
 
 /*
index 72507c630ceb563e9242145722b542b52731a7b3..203a4e944d9e43c53051725c084f542cceb8b7a3 100644 (file)
@@ -79,15 +79,11 @@ ENTRY(cpu_arm1020_proc_init)
  * cpu_arm1020_proc_fin()
  */
 ENTRY(cpu_arm1020_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm1020_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm1020_reset(loc)
index d27829805609f5793e23bb2fd0c67ac85993e955..1a511e765909957d81b463c17f0000b8893d3770 100644 (file)
@@ -79,15 +79,11 @@ ENTRY(cpu_arm1020e_proc_init)
  * cpu_arm1020e_proc_fin()
  */
 ENTRY(cpu_arm1020e_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm1020e_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm1020e_reset(loc)
index ce13e4a827de8ed9e787b11bf3a784b0bf803dab..1ffa4eb9c34f7d7d2f1b5ad5e3825daf67d14156 100644 (file)
@@ -68,15 +68,11 @@ ENTRY(cpu_arm1022_proc_init)
  * cpu_arm1022_proc_fin()
  */
 ENTRY(cpu_arm1022_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm1022_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm1022_reset(loc)
index 636672a29c6d1e58ad905850cba7374ba09d8f45..5697c34b95b0cdb38c31aad752c172b6990b5567 100644 (file)
@@ -68,15 +68,11 @@ ENTRY(cpu_arm1026_proc_init)
  * cpu_arm1026_proc_fin()
  */
 ENTRY(cpu_arm1026_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm1026_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm1026_reset(loc)
index 795dc615f43bb6f4b6513f4ac6a17a287911876e..64e0b327c7c5f504ec00757dcfd832d1fe56ac9e 100644 (file)
@@ -184,8 +184,6 @@ ENTRY(cpu_arm7_proc_init)
 
 ENTRY(cpu_arm6_proc_fin)
 ENTRY(cpu_arm7_proc_fin)
-               mov     r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-               msr     cpsr_c, r0
                mov     r0, #0x31                       @ ....S..DP...M
                mcr     p15, 0, r0, c1, c0, 0           @ disable caches
                mov     pc, lr
index 0b62de24466646d8b7e8aa65b84e8ac5191335f5..9d96824134fc4db4b0cd24f9df65c405717b4341 100644 (file)
@@ -54,15 +54,11 @@ ENTRY(cpu_arm720_proc_init)
                mov     pc, lr
 
 ENTRY(cpu_arm720_proc_fin)
-               stmfd   sp!, {lr}
-               mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-               msr     cpsr_c, ip
                mrc     p15, 0, r0, c1, c0, 0
                bic     r0, r0, #0x1000                 @ ...i............
                bic     r0, r0, #0x000e                 @ ............wca.
                mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-               mcr     p15, 0, r1, c7, c7, 0           @ invalidate cache
-               ldmfd   sp!, {pc}
+               mov     pc, lr
 
 /*
  * Function: arm720_proc_do_idle(void)
index 01860cdeb2ec3df451947f325c7d132449820717..6c1a9ab059aedb2f48e0d2bff8b823b3bb306dab 100644 (file)
@@ -36,15 +36,11 @@ ENTRY(cpu_arm740_switch_mm)
  * cpu_arm740_proc_fin()
  */
 ENTRY(cpu_arm740_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
        mrc     p15, 0, r0, c1, c0, 0
        bic     r0, r0, #0x3f000000             @ bank/f/lock/s
        bic     r0, r0, #0x0000000c             @ w-buffer/cache
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       mcr     p15, 0, r0, c7, c0, 0           @ invalidate cache
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm740_reset(loc)
index 1201b98638298087063d3ec02eefd3a7e58d9aa6..6a850dbba22e5ff7be9aae70476489feeaaeef18 100644 (file)
@@ -36,8 +36,6 @@ ENTRY(cpu_arm7tdmi_switch_mm)
  * cpu_arm7tdmi_proc_fin()
  */
 ENTRY(cpu_arm7tdmi_proc_fin)
-               mov     r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-               msr     cpsr_c, r0
                mov     pc, lr
 
 /*
index 8be81992645d8d814517510ea473d85c604888bd..86f80aa56216b8ecf3159c090a83eeb2da372820 100644 (file)
@@ -69,19 +69,11 @@ ENTRY(cpu_arm920_proc_init)
  * cpu_arm920_proc_fin()
  */
 ENTRY(cpu_arm920_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
-       bl      arm920_flush_kern_cache_all
-#else
-       bl      v4wt_flush_kern_cache_all
-#endif
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm920_reset(loc)
index c0ff8e4b1074bac560f318a25c2715b89976c603..f76ce9b62883be61a1abe9baf67ae1a4ca4d8324 100644 (file)
@@ -71,19 +71,11 @@ ENTRY(cpu_arm922_proc_init)
  * cpu_arm922_proc_fin()
  */
 ENTRY(cpu_arm922_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
-       bl      arm922_flush_kern_cache_all
-#else
-       bl      v4wt_flush_kern_cache_all
-#endif
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm922_reset(loc)
index 3c6cffe400f685f4dc3e32ccf078ef726d88d625..657bd3f7c153bf033f704636a323339129bb5d11 100644 (file)
@@ -92,15 +92,11 @@ ENTRY(cpu_arm925_proc_init)
  * cpu_arm925_proc_fin()
  */
 ENTRY(cpu_arm925_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm925_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm925_reset(loc)
index 75b707c9cce1ad31c2adf960d99e99cb5a266f8d..73f1f3c689108fcade13d8dbb26e057105247645 100644 (file)
@@ -61,15 +61,11 @@ ENTRY(cpu_arm926_proc_init)
  * cpu_arm926_proc_fin()
  */
 ENTRY(cpu_arm926_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm926_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm926_reset(loc)
index 1af1657819eb8e32caf40dbbc148ca2c0259144f..fffb061a45a558ee8dc5883dcba4a0e64ef53311 100644 (file)
@@ -37,15 +37,11 @@ ENTRY(cpu_arm940_switch_mm)
  * cpu_arm940_proc_fin()
  */
 ENTRY(cpu_arm940_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm940_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x00001000             @ i-cache
        bic     r0, r0, #0x00000004             @ d-cache
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm940_reset(loc)
index 1664b6aaff794957723cfac21696e8a2af030f3b..249a6053760a357baa0dca13c3d67bf49ebf975e 100644 (file)
@@ -44,15 +44,11 @@ ENTRY(cpu_arm946_switch_mm)
  * cpu_arm946_proc_fin()
  */
 ENTRY(cpu_arm946_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      arm946_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x00001000             @ i-cache
        bic     r0, r0, #0x00000004             @ d-cache
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_arm946_reset(loc)
index 28545c29dbcda317db178a564a7a894f3a846f96..db475667fac2c95df3ab30fdabda084eab94c3f3 100644 (file)
@@ -36,8 +36,6 @@ ENTRY(cpu_arm9tdmi_switch_mm)
  * cpu_arm9tdmi_proc_fin()
  */
 ENTRY(cpu_arm9tdmi_proc_fin)
-               mov     r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-               msr     cpsr_c, r0
                mov     pc, lr
 
 /*
index 08f5ac237ad4e83e67b7540a9680d28c619edc41..7803fdf7002933da8e63a3383f9da818ecea724c 100644 (file)
@@ -39,17 +39,13 @@ ENTRY(cpu_fa526_proc_init)
  * cpu_fa526_proc_fin()
  */
 ENTRY(cpu_fa526_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      fa_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
        nop
        nop
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_fa526_reset(loc)
index 53e63234384992ed07daf2eb48da91eaa5fa4a7d..b304d0104a4ef9c240191e42b7e08460706408b8 100644 (file)
@@ -75,11 +75,6 @@ ENTRY(cpu_feroceon_proc_init)
  * cpu_feroceon_proc_fin()
  */
 ENTRY(cpu_feroceon_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      feroceon_flush_kern_cache_all
-
 #if defined(CONFIG_CACHE_FEROCEON_L2) && \
        !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
        mov     r0, #0
@@ -91,7 +86,7 @@ ENTRY(cpu_feroceon_proc_fin)
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_feroceon_reset(loc)
index caa31154e7dbf71417beebc71128e0d061fb17ce..5f6892fcc1671f28070f175bc6eeda03bbe614c5 100644 (file)
@@ -51,15 +51,11 @@ ENTRY(cpu_mohawk_proc_init)
  * cpu_mohawk_proc_fin()
  */
 ENTRY(cpu_mohawk_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      mohawk_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1800                 @ ...iz...........
        bic     r0, r0, #0x0006                 @ .............ca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_mohawk_reset(loc)
index 7b706b38990625c08ca3595ff19b6657fcbb0648..a201eb04b5e1a6327d1a5375c00b669ee7fc439c 100644 (file)
@@ -44,17 +44,13 @@ ENTRY(cpu_sa110_proc_init)
  * cpu_sa110_proc_fin()
  */
 ENTRY(cpu_sa110_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      v4wb_flush_kern_cache_all       @ clean caches
-1:     mov     r0, #0
+       mov     r0, #0
        mcr     p15, 0, r0, c15, c2, 2          @ Disable clock switching
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_sa110_reset(loc)
index 5c47760c206437c0fbe7219aebae464b19929c7b..7ddc4805bf97a6fe722f54b3a769974bfaa42a1b 100644 (file)
@@ -55,16 +55,12 @@ ENTRY(cpu_sa1100_proc_init)
  *  - Clean and turn off caches.
  */
 ENTRY(cpu_sa1100_proc_fin)
-       stmfd   sp!, {lr}
-       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
-       msr     cpsr_c, ip
-       bl      v4wb_flush_kern_cache_all
        mcr     p15, 0, ip, c15, c2, 2          @ Disable clock switching
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x000e                 @ ............wca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  * cpu_sa1100_reset(loc)
index 7a5337ed7d68b6b1112e59ede2ce2dd5ed630a5f..22aac85151966d3058ace5cdb24eb4a608605e16 100644 (file)
@@ -42,14 +42,11 @@ ENTRY(cpu_v6_proc_init)
        mov     pc, lr
 
 ENTRY(cpu_v6_proc_fin)
-       stmfd   sp!, {lr}
-       cpsid   if                              @ disable interrupts
-       bl      v6_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x0006                 @ .............ca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 
 /*
  *     cpu_v6_reset(loc)
@@ -239,7 +236,8 @@ __v6_proc_info:
        b       __v6_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
-       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
+       /* See also feat_v6_fixup() for HWCAP_TLS */
+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA|HWCAP_TLS
        .long   cpu_v6_name
        .long   v6_processor_functions
        .long   v6wbi_tlb_fns
@@ -262,7 +260,7 @@ __pj4_v6_proc_info:
        b       __v6_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
-       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
        .long   cpu_pj4_name
        .long   v6_processor_functions
        .long   v6wbi_tlb_fns
index 7aaf88a3b7aabb7a8a7268d435eda8aa78bd7671..6a8506d99ee9abbb0845f39d94d663f802c56885 100644 (file)
@@ -45,14 +45,11 @@ ENTRY(cpu_v7_proc_init)
 ENDPROC(cpu_v7_proc_init)
 
 ENTRY(cpu_v7_proc_fin)
-       stmfd   sp!, {lr}
-       cpsid   if                              @ disable interrupts
-       bl      v7_flush_kern_cache_all
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x0006                 @ .............ca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldmfd   sp!, {pc}
+       mov     pc, lr
 ENDPROC(cpu_v7_proc_fin)
 
 /*
@@ -344,7 +341,7 @@ __v7_proc_info:
        b       __v7_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
-       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
        .long   cpu_v7_name
        .long   v7_processor_functions
        .long   v7wbi_tlb_fns
index e5797f1c1db7d0dd4ccf06ff308655be1d2aa2a9..361a51e4903063ffc82f6831f3bee47e3a957860 100644 (file)
@@ -90,15 +90,11 @@ ENTRY(cpu_xsc3_proc_init)
  * cpu_xsc3_proc_fin()
  */
 ENTRY(cpu_xsc3_proc_fin)
-       str     lr, [sp, #-4]!
-       mov     r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
-       msr     cpsr_c, r0
-       bl      xsc3_flush_kern_cache_all       @ clean caches
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1800                 @ ...IZ...........
        bic     r0, r0, #0x0006                 @ .............CA.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldr     pc, [sp], #4
+       mov     pc, lr
 
 /*
  * cpu_xsc3_reset(loc)
index 63037e2162f201ba76ad34604c2cd09ab450d71b..14075979bcbac1a4bfe7ae346e97058de819d448 100644 (file)
@@ -124,15 +124,11 @@ ENTRY(cpu_xscale_proc_init)
  * cpu_xscale_proc_fin()
  */
 ENTRY(cpu_xscale_proc_fin)
-       str     lr, [sp, #-4]!
-       mov     r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
-       msr     cpsr_c, r0
-       bl      xscale_flush_kern_cache_all     @ clean caches
        mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
        bic     r0, r0, #0x1800                 @ ...IZ...........
        bic     r0, r0, #0x0006                 @ .............CA.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
-       ldr     pc, [sp], #4
+       mov     pc, lr
 
 /*
  * cpu_xscale_reset(loc)
index 19e09bdb1b8a4ea3e4d892f8ab753eee25d6cd0b..935993e1b1ef53f5372344cbc6a5c764186557b9 100644 (file)
@@ -35,7 +35,8 @@
  */
 
 struct arm_vmregion *
-arm_vmregion_alloc(struct arm_vmregion_head *head, size_t size, gfp_t gfp)
+arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
+                  size_t size, gfp_t gfp)
 {
        unsigned long addr = head->vm_start, end = head->vm_end - size;
        unsigned long flags;
@@ -58,7 +59,7 @@ arm_vmregion_alloc(struct arm_vmregion_head *head, size_t size, gfp_t gfp)
                        goto nospc;
                if ((addr + size) <= c->vm_start)
                        goto found;
-               addr = c->vm_end;
+               addr = ALIGN(c->vm_end, align);
                if (addr > end)
                        goto nospc;
        }
index 6b2cdbdf3a857a12162654140185d61616f77d49..15e9f044db9feab45a25d79eed9e1f0dce5a2a1a 100644 (file)
@@ -21,7 +21,7 @@ struct arm_vmregion {
        int                     vm_active;
 };
 
-struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, gfp_t);
+struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t);
 struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
 struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
 void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
index ce31f316ac75c1e72af3693a58633a10e50e7f7a..43f2b158237c71c99cc51f0e3d99066a05ee65cb 100644 (file)
@@ -359,7 +359,7 @@ static void __init iop3xx_atu_debug(void)
        DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD);
        DBG("ATU: IOP3XX_ATUCR=0x%08x\n", *IOP3XX_ATUCR);
 
-       hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort");
+       hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, 0, "imprecise external abort");
 }
 
 /* for platforms that might be host-bus-adapters */
index 6c8a02ad98e33f9a374fd62c58c5ea7630427f0c..85d3e55ca4a9c293c67d4b2557bb52d90f93d22f 100644 (file)
 #include <asm/mach/time.h>
 #include <mach/time.h>
 
+/*
+ * Minimum clocksource/clockevent timer range in seconds
+ */
+#define IOP_MIN_RANGE 4
+
 /*
  * IOP clocksource (free-running timer 1).
  */
@@ -44,27 +49,6 @@ static struct clocksource iop_clocksource = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init iop_clocksource_set_hz(struct clocksource *cs, unsigned int hz)
-{
-       u64 temp;
-       u32 shift;
-
-       /* Find shift and mult values for hz. */
-       shift = 32;
-       do {
-               temp = (u64) NSEC_PER_SEC << shift;
-               do_div(temp, hz);
-               if ((temp >> 32) == 0)
-                       break;
-       } while (--shift != 0);
-
-       cs->shift = shift;
-       cs->mult = (u32) temp;
-
-       printk(KERN_INFO "clocksource: %s uses shift %u mult %#x\n",
-              cs->name, cs->shift, cs->mult);
-}
-
 /*
  * IOP sched_clock() implementation via its clocksource.
  */
@@ -130,27 +114,6 @@ static struct clock_event_device iop_clockevent = {
        .set_mode       = iop_set_mode,
 };
 
-static void __init iop_clockevent_set_hz(struct clock_event_device *ce, unsigned int hz)
-{
-       u64 temp;
-       u32 shift;
-
-       /* Find shift and mult values for hz. */
-       shift = 32;
-       do {
-               temp = (u64) hz << shift;
-               do_div(temp, NSEC_PER_SEC);
-               if ((temp >> 32) == 0)
-                       break;
-       } while (--shift != 0);
-
-       ce->shift = shift;
-       ce->mult = (u32) temp;
-
-       printk(KERN_INFO "clockevent: %s uses shift %u mult %#lx\n",
-              ce->name, ce->shift, ce->mult);
-}
-
 static irqreturn_t
 iop_timer_interrupt(int irq, void *dev_id)
 {
@@ -190,7 +153,8 @@ void __init iop_init_time(unsigned long tick_rate)
         */
        write_tmr0(timer_ctl & ~IOP_TMR_EN);
        setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
-       iop_clockevent_set_hz(&iop_clockevent, tick_rate);
+       clockevents_calc_mult_shift(&iop_clockevent,
+                                   tick_rate, IOP_MIN_RANGE);
        iop_clockevent.max_delta_ns =
                clockevent_delta2ns(0xfffffffe, &iop_clockevent);
        iop_clockevent.min_delta_ns =
@@ -207,6 +171,7 @@ void __init iop_init_time(unsigned long tick_rate)
        write_trr1(0xffffffff);
        write_tcr1(0xffffffff);
        write_tmr1(timer_ctl);
-       iop_clocksource_set_hz(&iop_clocksource, tick_rate);
+       clocksource_calc_mult_shift(&iop_clocksource, tick_rate,
+                                   IOP_MIN_RANGE);
        clocksource_register(&iop_clocksource);
 }
diff --git a/arch/arm/plat-mxc/3ds_debugboard.c b/arch/arm/plat-mxc/3ds_debugboard.c
new file mode 100644 (file)
index 0000000..639c54a
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010 Jason Wang <jason77.wang@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+
+#include <mach/hardware.h>
+
+/* LAN9217 ethernet base address */
+#define LAN9217_BASE_ADDR(n)   (n + 0x0)
+/* External UART */
+#define UARTA_BASE_ADDR(n)     (n + 0x8000)
+#define UARTB_BASE_ADDR(n)     (n + 0x10000)
+
+#define BOARD_IO_ADDR(n)       (n + 0x20000)
+/* LED switchs */
+#define LED_SWITCH_REG         0x00
+/* buttons */
+#define SWITCH_BUTTONS_REG     0x08
+/* status, interrupt */
+#define INTR_STATUS_REG        0x10
+#define INTR_MASK_REG          0x38
+#define INTR_RESET_REG         0x20
+/* magic word for debug CPLD */
+#define MAGIC_NUMBER1_REG      0x40
+#define MAGIC_NUMBER2_REG      0x48
+/* CPLD code version */
+#define CPLD_CODE_VER_REG      0x50
+/* magic word for debug CPLD */
+#define MAGIC_NUMBER3_REG      0x58
+/* module reset register*/
+#define MODULE_RESET_REG       0x60
+/* CPU ID and Personality ID */
+#define MCU_BOARD_ID_REG       0x68
+
+#define MXC_IRQ_TO_EXPIO(irq)   ((irq) - MXC_BOARD_IRQ_START)
+#define MXC_IRQ_TO_GPIO(irq)   ((irq) - MXC_INTERNAL_IRQS)
+
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
+#define MXC_MAX_EXP_IO_LINES   16
+
+/* interrupts like external uart , external ethernet etc*/
+#define EXPIO_INT_ENET         (MXC_BOARD_IRQ_START + 0)
+#define EXPIO_INT_XUART_A      (MXC_BOARD_IRQ_START + 1)
+#define EXPIO_INT_XUART_B      (MXC_BOARD_IRQ_START + 2)
+#define EXPIO_INT_BUTTON_A     (MXC_BOARD_IRQ_START + 3)
+#define EXPIO_INT_BUTTON_B     (MXC_BOARD_IRQ_START + 4)
+
+static void __iomem *brd_io;
+static void expio_ack_irq(u32 irq);
+
+static struct resource smsc911x_resources[] = {
+       {
+               .flags = IORESOURCE_MEM,
+       } , {
+               .start = EXPIO_INT_ENET,
+               .end = EXPIO_INT_ENET,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .flags = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY,
+};
+
+static struct platform_device smsc_lan9217_device = {
+       .name = "smsc911x",
+       .id = 0,
+       .dev = {
+               .platform_data = &smsc911x_config,
+       },
+       .num_resources = ARRAY_SIZE(smsc911x_resources),
+       .resource = smsc911x_resources,
+};
+
+static void mxc_expio_irq_handler(u32 irq, struct irq_desc *desc)
+{
+       u32 imr_val;
+       u32 int_valid;
+       u32 expio_irq;
+
+       desc->chip->mask(irq);  /* irq = gpio irq number */
+
+       imr_val = __raw_readw(brd_io + INTR_MASK_REG);
+       int_valid = __raw_readw(brd_io + INTR_STATUS_REG) & ~imr_val;
+
+       expio_irq = MXC_BOARD_IRQ_START;
+       for (; int_valid != 0; int_valid >>= 1, expio_irq++) {
+               struct irq_desc *d;
+               if ((int_valid & 1) == 0)
+                       continue;
+               d = irq_desc + expio_irq;
+               if (unlikely(!(d->handle_irq)))
+                       pr_err("\nEXPIO irq: %d unhandled\n", expio_irq);
+               else
+                       d->handle_irq(expio_irq, d);
+       }
+
+       desc->chip->ack(irq);
+       desc->chip->unmask(irq);
+}
+
+/*
+ * Disable an expio pin's interrupt by setting the bit in the imr.
+ * Irq is an expio virtual irq number
+ */
+static void expio_mask_irq(u32 irq)
+{
+       u16 reg;
+       u32 expio = MXC_IRQ_TO_EXPIO(irq);
+
+       reg = __raw_readw(brd_io + INTR_MASK_REG);
+       reg |= (1 << expio);
+       __raw_writew(reg, brd_io + INTR_MASK_REG);
+}
+
+static void expio_ack_irq(u32 irq)
+{
+       u32 expio = MXC_IRQ_TO_EXPIO(irq);
+
+       __raw_writew(1 << expio, brd_io + INTR_RESET_REG);
+       __raw_writew(0, brd_io + INTR_RESET_REG);
+       expio_mask_irq(irq);
+}
+
+static void expio_unmask_irq(u32 irq)
+{
+       u16 reg;
+       u32 expio = MXC_IRQ_TO_EXPIO(irq);
+
+       reg = __raw_readw(brd_io + INTR_MASK_REG);
+       reg &= ~(1 << expio);
+       __raw_writew(reg, brd_io + INTR_MASK_REG);
+}
+
+static struct irq_chip expio_irq_chip = {
+       .ack = expio_ack_irq,
+       .mask = expio_mask_irq,
+       .unmask = expio_unmask_irq,
+};
+
+int __init mxc_expio_init(u32 base, u32 p_irq)
+{
+       int i;
+
+       brd_io = ioremap(BOARD_IO_ADDR(base), SZ_4K);
+       if (brd_io == NULL)
+               return -ENOMEM;
+
+       if ((__raw_readw(brd_io + MAGIC_NUMBER1_REG) != 0xAAAA) ||
+           (__raw_readw(brd_io + MAGIC_NUMBER2_REG) != 0x5555) ||
+           (__raw_readw(brd_io + MAGIC_NUMBER3_REG) != 0xCAFE)) {
+               pr_info("3-Stack Debug board not detected\n");
+               iounmap(brd_io);
+               brd_io = NULL;
+               return -ENODEV;
+       }
+
+       pr_info("3-Stack Debug board detected, rev = 0x%04X\n",
+               readw(brd_io + CPLD_CODE_VER_REG));
+
+       /*
+        * Configure INT line as GPIO input
+        */
+       gpio_request(MXC_IRQ_TO_GPIO(p_irq), "expio_pirq");
+       gpio_direction_input(MXC_IRQ_TO_GPIO(p_irq));
+
+       /* disable the interrupt and clear the status */
+       __raw_writew(0, brd_io + INTR_MASK_REG);
+       __raw_writew(0xFFFF, brd_io + INTR_RESET_REG);
+       __raw_writew(0, brd_io + INTR_RESET_REG);
+       __raw_writew(0x1F, brd_io + INTR_MASK_REG);
+       for (i = MXC_EXP_IO_BASE;
+            i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES); i++) {
+               set_irq_chip(i, &expio_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+       set_irq_type(p_irq, IRQF_TRIGGER_LOW);
+       set_irq_chained_handler(p_irq, mxc_expio_irq_handler);
+
+       /* Register Lan device on the debugboard */
+       smsc911x_resources[0].start = LAN9217_BASE_ADDR(base);
+       smsc911x_resources[0].end = LAN9217_BASE_ADDR(base) + 0x100 - 1;
+       platform_device_register(&smsc_lan9217_device);
+
+       return 0;
+}
index 7f7ad6f289bd53383ed5ed952099d62c2a4f52b1..0527e65318f4a647b5b00192ce08ba47368ce5f8 100644 (file)
@@ -1,5 +1,7 @@
 if ARCH_MXC
 
+source "arch/arm/plat-mxc/devices/Kconfig"
+
 menu "Freescale MXC Implementations"
 
 choice
@@ -8,15 +10,12 @@ choice
 
 config ARCH_MX1
        bool "MX1-based"
-       select CPU_ARM920T
-       select IMX_HAVE_IOMUX_V1
+       select SOC_IMX1
        help
          This enables support for systems based on the Freescale i.MX1 family
 
 config ARCH_MX2
        bool "MX2-based"
-       select CPU_ARM926T
-       select IMX_HAVE_IOMUX_V1
        help
          This enables support for systems based on the Freescale i.MX2 family
 
@@ -25,6 +24,7 @@ config ARCH_MX25
        select CPU_ARM926T
        select ARCH_MXC_IOMUX_V3
        select HAVE_FB_IMX
+       select ARCH_MXC_AUDMUX_V2
        help
          This enables support for systems based on the Freescale i.MX25 family
 
@@ -48,8 +48,7 @@ config ARCH_MX5
 
 endchoice
 
-source "arch/arm/mach-mx1/Kconfig"
-source "arch/arm/mach-mx2/Kconfig"
+source "arch/arm/mach-imx/Kconfig"
 source "arch/arm/mach-mx3/Kconfig"
 source "arch/arm/mach-mx25/Kconfig"
 source "arch/arm/mach-mxc91231/Kconfig"
@@ -81,6 +80,17 @@ config MXC_PWM
        help
          Enable support for the i.MX PWM controller(s).
 
+config MXC_DEBUG_BOARD
+       bool "Enable MXC debug board(for 3-stack)"
+       help
+         The debug board is an integral part of the MXC 3-stack(PDK)
+         platforms, it can be attached or removed from the peripheral
+         board. On debug board, several debug devices(ethernet, UART,
+         buttons, LEDs and JTAG) are implemented. Between the MCU and
+         these devices, a CPLD is added as a bridge which performs
+         data/address de-multiplexing and decode, signal level shift,
+         interrupt control and various board functions.
+
 config MXC_ULPI
        bool
 
index 895bc3c5e0c0a5f709018a9f855536961d1a3da6..78d405ed861656ef83182a7242c385dcab805ce0 100644 (file)
@@ -8,8 +8,6 @@ obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o
 # MX51 uses the TZIC interrupt controller, older platforms use AVIC (irq.o)
 obj-$(CONFIG_MXC_TZIC) += tzic.o
 
-obj-$(CONFIG_ARCH_MX1) += dma-mx1-mx2.o
-obj-$(CONFIG_ARCH_MX2) += dma-mx1-mx2.o
 obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
 obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
 obj-$(CONFIG_MXC_PWM)  += pwm.o
@@ -17,7 +15,10 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
 obj-$(CONFIG_MXC_ULPI) += ulpi.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
+obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
 ifdef CONFIG_SND_IMX_SOC
 obj-y += ssi-fiq.o
 obj-y += ssi-fiq-ksym.o
 endif
+
+obj-y += devices/
index b62917ca3f954bba4e2b5925879ed96c55f24738..1180bef7664b3ca34359d37940a2fd20081b7017 100644 (file)
  * 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>
index 0c2cc5cd4d83ac6ec5129dcba1a896eab8230f00..f9e7cdbd000568a562ac4bd062a550df73f3a853 100644 (file)
  * 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>
@@ -191,6 +187,7 @@ static int mxc_audmux_v2_init(void)
 {
        int ret;
 
+#if defined(CONFIG_ARCH_MX3)
        if (cpu_is_mx31())
                audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR);
 
@@ -204,7 +201,19 @@ static int mxc_audmux_v2_init(void)
                }
                audmux_base = MX35_IO_ADDRESS(MX35_AUDMUX_BASE_ADDR);
        }
-
+#endif
+#if defined(CONFIG_ARCH_MX25)
+       if (cpu_is_mx25()) {
+               audmux_clk = clk_get(NULL, "audmux");
+               if (IS_ERR(audmux_clk)) {
+                       ret = PTR_ERR(audmux_clk);
+                       printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
+                                       ret);
+                       return ret;
+               }
+               audmux_base = MX25_IO_ADDRESS(MX25_AUDMUX_BASE_ADDR);
+       }
+#endif
        audmux_debugfs_init();
 
        return 0;
index 323ff8ccc877161042a72bbf309c955878160966..2ed3ab173addcae894a1c52190e7cc9419dddc90 100644 (file)
@@ -52,13 +52,14 @@ static void __clk_disable(struct clk *clk)
 {
        if (clk == NULL || IS_ERR(clk))
                return;
-
-       __clk_disable(clk->parent);
-       __clk_disable(clk->secondary);
-
        WARN_ON(!clk->usecount);
-       if (!(--clk->usecount) && clk->disable)
-               clk->disable(clk);
+
+       if (!(--clk->usecount)) {
+               if (clk->disable)
+                       clk->disable(clk);
+               __clk_disable(clk->parent);
+               __clk_disable(clk->secondary);
+       }
 }
 
 static int __clk_enable(struct clk *clk)
@@ -66,12 +67,13 @@ static int __clk_enable(struct clk *clk)
        if (clk == NULL || IS_ERR(clk))
                return -EINVAL;
 
-       __clk_enable(clk->parent);
-       __clk_enable(clk->secondary);
-
-       if (clk->usecount++ == 0 && clk->enable)
-               clk->enable(clk);
+       if (clk->usecount++ == 0) {
+               __clk_enable(clk->parent);
+               __clk_enable(clk->secondary);
 
+               if (clk->enable)
+                       clk->enable(clk);
+       }
        return 0;
 }
 
@@ -160,17 +162,28 @@ EXPORT_SYMBOL(clk_set_rate);
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
        int ret = -EINVAL;
+       struct clk *old;
 
        if (clk == NULL || IS_ERR(clk) || parent == NULL ||
            IS_ERR(parent) || clk->set_parent == NULL)
                return ret;
 
+       if (clk->usecount)
+               clk_enable(parent);
+
        mutex_lock(&clocks_mutex);
        ret = clk->set_parent(clk, parent);
-       if (ret == 0)
+       if (ret == 0) {
+               old = clk->parent;
                clk->parent = parent;
+       } else {
+               old = parent;
+       }
        mutex_unlock(&clocks_mutex);
 
+       if (clk->usecount)
+               clk_disable(old);
+
        return ret;
 }
 EXPORT_SYMBOL(clk_set_parent);
index 56f2fb5cc456433e6a7f4d23b129a77004b67655..735776d8495636fd8e7429fc2d21b9797bd575ff 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <mach/common.h>
 
@@ -35,3 +36,35 @@ int __init mxc_register_device(struct platform_device *pdev, void *data)
        return ret;
 }
 
+struct platform_device *__init imx_add_platform_device(const char *name, int id,
+               const struct resource *res, unsigned int num_resources,
+               const void *data, size_t size_data)
+{
+       int ret = -ENOMEM;
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc(name, id);
+       if (!pdev)
+               goto err;
+
+       if (res) {
+               ret = platform_device_add_resources(pdev, res, num_resources);
+               if (ret)
+                       goto err;
+       }
+
+       if (data) {
+               ret = platform_device_add_data(pdev, data, size_data);
+               if (ret)
+                       goto err;
+       }
+
+       ret = platform_device_add(pdev);
+       if (ret) {
+err:
+               platform_device_put(pdev);
+               return ERR_PTR(ret);
+       }
+
+       return pdev;
+}
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
new file mode 100644 (file)
index 0000000..9ab784b
--- /dev/null
@@ -0,0 +1,15 @@
+config IMX_HAVE_PLATFORM_FLEXCAN
+       select HAVE_CAN_FLEXCAN
+       bool
+
+config IMX_HAVE_PLATFORM_IMX_I2C
+       bool
+
+config IMX_HAVE_PLATFORM_IMX_UART
+       bool
+
+config IMX_HAVE_PLATFORM_MXC_NAND
+       bool
+
+config IMX_HAVE_PLATFORM_SPI_IMX
+       bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
new file mode 100644 (file)
index 0000000..347da51
--- /dev/null
@@ -0,0 +1,8 @@
+ifdef CONFIG_CAN_FLEXCAN
+# the ifdef can be removed once the flexcan driver has been merged
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) +=  platform-flexcan.o
+endif
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) +=  platform-spi_imx.o
diff --git a/arch/arm/plat-mxc/devices/platform-flexcan.c b/arch/arm/plat-mxc/devices/platform-flexcan.c
new file mode 100644 (file)
index 0000000..5e97a01
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.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.
+ */
+
+#include <mach/devices-common.h>
+
+struct platform_device *__init imx_add_flexcan(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irq,
+               const struct flexcan_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = iobase,
+                       .end = iobase + iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irq,
+                       .end = irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("flexcan", id, res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-imx-i2c.c b/arch/arm/plat-mxc/devices/platform-imx-i2c.c
new file mode 100644 (file)
index 0000000..d0af9f7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/devices-common.h>
+
+struct platform_device *__init imx_add_imx_i2c(int id,
+               resource_size_t iobase, resource_size_t iosize, int irq,
+               const struct imxi2c_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = iobase,
+                       .end = iobase + iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irq,
+                       .end = irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("imx-i2c", id, res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-imx-uart.c b/arch/arm/plat-mxc/devices/platform-imx-uart.c
new file mode 100644 (file)
index 0000000..fa3dff1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <mach/devices-common.h>
+
+struct platform_device *__init imx_add_imx_uart_3irq(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irqrx, resource_size_t irqtx,
+               resource_size_t irqrts,
+               const struct imxuart_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = iobase,
+                       .end = iobase + iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irqrx,
+                       .end = irqrx,
+                       .flags = IORESOURCE_IRQ,
+               }, {
+                       .start = irqtx,
+                       .end = irqtx,
+                       .flags = IORESOURCE_IRQ,
+               }, {
+                       .start = irqrts,
+                       .end = irqrx,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
+
+struct platform_device *__init imx_add_imx_uart_1irq(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irq,
+               const struct imxuart_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = iobase,
+                       .end = iobase + iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irq,
+                       .end = irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_nand.c b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
new file mode 100644 (file)
index 0000000..1c28641
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <asm/sizes.h>
+#include <mach/devices-common.h>
+
+static struct platform_device *__init imx_add_mxc_nand(resource_size_t iobase,
+               int irq, const struct mxc_nand_platform_data *pdata,
+               resource_size_t iosize)
+{
+       static int id = 0;
+       
+       struct resource res[] = {
+               {
+                       .start = iobase,
+                       .end = iobase + iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irq,
+                       .end = irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("mxc_nand", id++, res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
+
+struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
+               int irq, const struct mxc_nand_platform_data *pdata)
+{
+       return imx_add_mxc_nand(iobase, irq, pdata, SZ_4K);
+}
+
+struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
+               int irq, const struct mxc_nand_platform_data *pdata)
+{
+       return imx_add_mxc_nand(iobase, irq, pdata, SZ_8K);
+}
diff --git a/arch/arm/plat-mxc/devices/platform-spi_imx.c b/arch/arm/plat-mxc/devices/platform-spi_imx.c
new file mode 100644 (file)
index 0000000..2831a6d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <asm/sizes.h>
+#include <mach/devices-common.h>
+
+struct platform_device *__init imx_add_spi_imx(int id,
+               resource_size_t iobase, resource_size_t iosize, int irq,
+               const struct spi_imx_master *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = iobase,
+                       .end = iobase + iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irq,
+                       .end = irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("spi_imx", id, res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
index 2a8646173c2f57b3270bfde937095efb606e3135..35a064ff02ba61a66b4f0425728baa4b7f74cda6 100644 (file)
  * 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/platform_device.h>
 int mxc_initialize_usb_hw(int port, unsigned int flags)
 {
        unsigned int v;
-#ifdef CONFIG_ARCH_MX3
+#if defined(CONFIG_ARCH_MX25)
+       if (cpu_is_mx25()) {
+               v = readl(MX25_IO_ADDRESS(MX25_OTG_BASE_ADDR +
+                                    USBCTRL_OTGBASE_OFFSET));
+
+               switch (port) {
+               case 0: /* OTG port */
+                       v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT);
+                       v |= (flags & MXC_EHCI_INTERFACE_MASK)
+                                       << MX35_OTG_SIC_SHIFT;
+                       if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+                               v |= MX35_OTG_PM_BIT;
+
+                       break;
+               case 1: /* H1 port */
+                       v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_TLL_BIT |
+                               MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT);
+                       v |= (flags & MXC_EHCI_INTERFACE_MASK)
+                                               << MX35_H1_SIC_SHIFT;
+                       if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+                               v |= MX35_H1_PM_BIT;
+
+                       if (!(flags & MXC_EHCI_TTL_ENABLED))
+                               v |= MX35_H1_TLL_BIT;
+
+                       if (flags & MXC_EHCI_INTERNAL_PHY)
+                               v |= MX35_H1_USBTE_BIT;
+
+                       if (flags & MXC_EHCI_IPPUE_DOWN)
+                               v |= MX35_H1_IPPUE_DOWN_BIT;
+
+                       if (flags & MXC_EHCI_IPPUE_UP)
+                               v |= MX35_H1_IPPUE_UP_BIT;
+
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               writel(v, MX25_IO_ADDRESS(MX25_OTG_BASE_ADDR +
+                                    USBCTRL_OTGBASE_OFFSET));
+               return 0;
+       }
+#endif /* CONFIG_ARCH_MX25 */
+#if defined(CONFIG_ARCH_MX3)
        if (cpu_is_mx31()) {
                v = readl(MX31_IO_ADDRESS(MX31_OTG_BASE_ADDR +
                                     USBCTRL_OTGBASE_OFFSET));
index 71437c61cfd70f65e1aafd73095faf3718e3e8e3..57ec4a896a5d983556ebae058dbf52293ebe669e 100644 (file)
@@ -214,13 +214,16 @@ static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
        struct mxc_gpio_port *port =
                container_of(chip, struct mxc_gpio_port, chip);
        u32 l;
+       unsigned long flags;
 
+       spin_lock_irqsave(&port->lock, flags);
        l = __raw_readl(port->base + GPIO_GDIR);
        if (dir)
                l |= 1 << offset;
        else
                l &= ~(1 << offset);
        __raw_writel(l, port->base + GPIO_GDIR);
+       spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -229,9 +232,12 @@ static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                container_of(chip, struct mxc_gpio_port, chip);
        void __iomem *reg = port->base + GPIO_DR;
        u32 l;
+       unsigned long flags;
 
+       spin_lock_irqsave(&port->lock, flags);
        l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
        __raw_writel(l, reg);
+       spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -285,6 +291,8 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
                port[i].chip.base = i * 32;
                port[i].chip.ngpio = 32;
 
+               spin_lock_init(&port[i].lock);
+
                /* its a serious configuration bug when it fails */
                BUG_ON( gpiochip_add(&port[i].chip) < 0 );
 
@@ -292,6 +300,12 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
                        /* setup one handler for each entry */
                        set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler);
                        set_irq_data(port[i].irq, &port[i]);
+                       if (port[i].irq_high) {
+                               /* setup handler for GPIO 16 to 31 */
+                               set_irq_chained_handler(port[i].irq_high,
+                                               mx3_gpio_irq_handler);
+                               set_irq_data(port[i].irq_high, &port[i]);
+                       }
                }
        }
 
diff --git a/arch/arm/plat-mxc/include/mach/3ds_debugboard.h b/arch/arm/plat-mxc/include/mach/3ds_debugboard.h
new file mode 100644 (file)
index 0000000..a384fdd
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ASM_ARCH_MXC_3DS_DB_H__
+#define __ASM_ARCH_MXC_3DS_DB_H__
+
+extern int __init mxc_expio_init(u32 base, u32 p_irq);
+
+#endif /* __ASM_ARCH_MXC_3DS_DB_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h b/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h
deleted file mode 100644 (file)
index 0376c13..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>.
- * 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 __ASM_ARCH_MXC_BOARD_ARMADILLO5X0_H__
-#define __ASM_ARCH_MXC_BOARD_ARMADILLO5X0_H__
-
-#endif
diff --git a/arch/arm/plat-mxc/include/mach/board-kzmarm11.h b/arch/arm/plat-mxc/include/mach/board-kzmarm11.h
deleted file mode 100644 (file)
index 93cc66f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *  Copyright (C) 2009  Yoichi Yuasa <yuasa@linux-mips.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __ARM_ARCH_BOARD_KZM_ARM11_H
-#define __ARM_ARCH_BOARD_KZM_ARM11_H
-
-/*
- *  KZM-ARM11-01 Board Control Registers on FPGA
- */
-#define KZM_ARM11_CTL1         (MX31_CS4_BASE_ADDR + 0x1000)
-#define KZM_ARM11_CTL2         (MX31_CS4_BASE_ADDR + 0x1001)
-#define KZM_ARM11_RSW1         (MX31_CS4_BASE_ADDR + 0x1002)
-#define KZM_ARM11_BACK_LIGHT   (MX31_CS4_BASE_ADDR + 0x1004)
-#define KZM_ARM11_FPGA_REV     (MX31_CS4_BASE_ADDR + 0x1008)
-#define KZM_ARM11_7SEG_LED     (MX31_CS4_BASE_ADDR + 0x1010)
-#define KZM_ARM11_LEDS         (MX31_CS4_BASE_ADDR + 0x1020)
-#define KZM_ARM11_DIPSW2       (MX31_CS4_BASE_ADDR + 0x1003)
-
-/*
- * External UART for touch panel on FPGA
- */
-#define KZM_ARM11_16550                (MX31_CS4_BASE_ADDR + 0x1050)
-
-#endif /* __ARM_ARCH_BOARD_KZM_ARM11_H */
-
diff --git a/arch/arm/plat-mxc/include/mach/board-mx21ads.h b/arch/arm/plat-mxc/include/mach/board-mx21ads.h
deleted file mode 100644 (file)
index 0cf4fa2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef __ASM_ARCH_MXC_BOARD_MX21ADS_H__
-#define __ASM_ARCH_MXC_BOARD_MX21ADS_H__
-
-/*
- * Memory-mapped I/O on MX21ADS base board
- */
-#define MX21ADS_MMIO_BASE_ADDR   0xF5000000
-#define MX21ADS_MMIO_SIZE        SZ_16M
-
-#define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
-               (MX21ADS_MMIO_BASE_ADDR + (offset))
-
-#define MX21ADS_CS8900A_IRQ         IRQ_GPIOE(11)
-#define MX21ADS_CS8900A_IOBASE_REG  MX21ADS_REG_ADDR(0x000000)
-#define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000)
-#define MX21ADS_VERSION_REG         MX21ADS_REG_ADDR(0x400000)
-#define MX21ADS_IO_REG              MX21ADS_REG_ADDR(0x800000)
-
-/* MX21ADS_IO_REG bit definitions */
-#define MX21ADS_IO_SD_WP        0x0001 /* read */
-#define MX21ADS_IO_TP6          0x0001 /* write */
-#define MX21ADS_IO_SW_SEL       0x0002 /* read */
-#define MX21ADS_IO_TP7          0x0002 /* write */
-#define MX21ADS_IO_RESET_E_UART 0x0004
-#define MX21ADS_IO_RESET_BASE   0x0008
-#define MX21ADS_IO_CSI_CTL2     0x0010
-#define MX21ADS_IO_CSI_CTL1     0x0020
-#define MX21ADS_IO_CSI_CTL0     0x0040
-#define MX21ADS_IO_UART1_EN     0x0080
-#define MX21ADS_IO_UART4_EN     0x0100
-#define MX21ADS_IO_LCDON        0x0200
-#define MX21ADS_IO_IRDA_EN      0x0400
-#define MX21ADS_IO_IRDA_FIR_SEL 0x0800
-#define MX21ADS_IO_IRDA_MD0_B   0x1000
-#define MX21ADS_IO_IRDA_MD1     0x2000
-#define MX21ADS_IO_LED4_ON      0x4000
-#define MX21ADS_IO_LED3_ON      0x8000
-
-#endif                         /* __ASM_ARCH_MXC_BOARD_MX21ADS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27ads.h b/arch/arm/plat-mxc/include/mach/board-mx27ads.h
deleted file mode 100644 (file)
index 7776d23..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef __ASM_ARCH_MXC_BOARD_MX27ADS_H__
-#define __ASM_ARCH_MXC_BOARD_MX27ADS_H__
-
-/* external interrupt multiplexer */
-#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
-
-#define MXC_VIRTUAL_INTS_BASE  (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES)
-#define MXC_SDIO1_CARD_IRQ     MXC_VIRTUAL_INTS_BASE
-#define MXC_SDIO2_CARD_IRQ     (MXC_VIRTUAL_INTS_BASE + 1)
-#define MXC_SDIO3_CARD_IRQ     (MXC_VIRTUAL_INTS_BASE + 2)
-
-#define MXC_MAX_BOARD_INTS      (MXC_MAX_EXP_IO_LINES + \
-                               MXC_MAX_VIRTUAL_INTS)
-
-/*
- * @name Memory Size parameters
- */
-
-/*
- * Size of SDRAM memory
- */
-#define SDRAM_MEM_SIZE          SZ_128M
-
-/*
- * PBC Controller parameters
- */
-
-/*
- * Base address of PBC controller, CS4
- */
-#define PBC_BASE_ADDRESS        0xf4300000
-#define PBC_REG_ADDR(offset)    (void __force __iomem *) \
-               (PBC_BASE_ADDRESS + (offset))
-
-/*
- * PBC Interupt name definitions
- */
-#define PBC_GPIO1_0  0
-#define PBC_GPIO1_1  1
-#define PBC_GPIO1_2  2
-#define PBC_GPIO1_3  3
-#define PBC_GPIO1_4  4
-#define PBC_GPIO1_5  5
-
-#define PBC_INTR_MAX_NUM 6
-#define PBC_INTR_SHARED_MAX_NUM 8
-
-/* When the PBC address connection is fixed in h/w, defined as 1 */
-#define PBC_ADDR_SH             0
-
-/* Offsets for the PBC Controller register */
-/*
- * PBC Board version register offset
- */
-#define PBC_VERSION_REG         PBC_REG_ADDR(0x00000 >> PBC_ADDR_SH)
-/*
- * PBC Board control register 1 set address.
- */
-#define PBC_BCTRL1_SET_REG      PBC_REG_ADDR(0x00008 >> PBC_ADDR_SH)
-/*
- * PBC Board control register 1 clear address.
- */
-#define PBC_BCTRL1_CLEAR_REG    PBC_REG_ADDR(0x0000C >> PBC_ADDR_SH)
-/*
- * PBC Board control register 2 set address.
- */
-#define PBC_BCTRL2_SET_REG      PBC_REG_ADDR(0x00010 >> PBC_ADDR_SH)
-/*
- * PBC Board control register 2 clear address.
- */
-#define PBC_BCTRL2_CLEAR_REG    PBC_REG_ADDR(0x00014 >> PBC_ADDR_SH)
-/*
- * PBC Board control register 3 set address.
- */
-#define PBC_BCTRL3_SET_REG      PBC_REG_ADDR(0x00018 >> PBC_ADDR_SH)
-/*
- * PBC Board control register 3 clear address.
- */
-#define PBC_BCTRL3_CLEAR_REG    PBC_REG_ADDR(0x0001C >> PBC_ADDR_SH)
-/*
- * PBC Board control register 3 set address.
- */
-#define PBC_BCTRL4_SET_REG      PBC_REG_ADDR(0x00020 >> PBC_ADDR_SH)
-/*
- * PBC Board control register 4 clear address.
- */
-#define PBC_BCTRL4_CLEAR_REG    PBC_REG_ADDR(0x00024 >> PBC_ADDR_SH)
-/*PBC_ADDR_SH
- * PBC Board status register 1.
- */
-#define PBC_BSTAT1_REG          PBC_REG_ADDR(0x00028 >> PBC_ADDR_SH)
-/*
- * PBC Board interrupt status register.
- */
-#define PBC_INTSTATUS_REG       PBC_REG_ADDR(0x0002C >> PBC_ADDR_SH)
-/*
- * PBC Board interrupt current status register.
- */
-#define PBC_INTCURR_STATUS_REG  PBC_REG_ADDR(0x00034 >> PBC_ADDR_SH)
-/*
- * PBC Interrupt mask register set address.
- */
-#define PBC_INTMASK_SET_REG     PBC_REG_ADDR(0x00038 >> PBC_ADDR_SH)
-/*
- * PBC Interrupt mask register clear address.
- */
-#define PBC_INTMASK_CLEAR_REG   PBC_REG_ADDR(0x0003C >> PBC_ADDR_SH)
-/*
- * External UART A.
- */
-#define PBC_SC16C652_UARTA_REG  PBC_REG_ADDR(0x20000 >> PBC_ADDR_SH)
-/*
- * UART 4 Expanding Signal Status.
- */
-#define PBC_UART_STATUS_REG     PBC_REG_ADDR(0x22000 >> PBC_ADDR_SH)
-/*
- * UART 4 Expanding Signal Control Set.
- */
-#define PBC_UCTRL_SET_REG       PBC_REG_ADDR(0x24000 >> PBC_ADDR_SH)
-/*
- * UART 4 Expanding Signal Control Clear.
- */
-#define PBC_UCTRL_CLR_REG       PBC_REG_ADDR(0x26000 >> PBC_ADDR_SH)
-/*
- * Ethernet Controller IO base address.
- */
-#define PBC_CS8900A_IOBASE_REG  PBC_REG_ADDR(0x40000 >> PBC_ADDR_SH)
-/*
- * Ethernet Controller Memory base address.
- */
-#define PBC_CS8900A_MEMBASE_REG PBC_REG_ADDR(0x42000 >> PBC_ADDR_SH)
-/*
- * Ethernet Controller DMA base address.
- */
-#define PBC_CS8900A_DMABASE_REG PBC_REG_ADDR(0x44000 >> PBC_ADDR_SH)
-
-/* PBC Board Version Register bit definition */
-#define PBC_VERSION_ADS         0x8000 /* Bit15=1 means version for ads */
-#define PBC_VERSION_EVB_REVB    0x4000 /* BIT14=1 means version for evb revb */
-
-/* PBC Board Control Register 1 bit definitions */
-#define PBC_BCTRL1_ERST         0x0001 /* Ethernet Reset */
-#define PBC_BCTRL1_URST         0x0002 /* Reset External UART controller */
-#define PBC_BCTRL1_FRST         0x0004 /* FEC Reset */
-#define PBC_BCTRL1_ESLEEP       0x0010 /* Enable ethernet Sleep */
-#define PBC_BCTRL1_LCDON        0x0800 /* Enable the LCD */
-
-/* PBC Board Control Register 2 bit definitions */
-#define PBC_BCTRL2_VCC_EN       0x0004 /*   Enable VCC */
-#define PBC_BCTRL2_VPP_EN       0x0008 /*   Enable Vpp */
-#define PBC_BCTRL2_ATAFEC_EN    0X0010
-#define PBC_BCTRL2_ATAFEC_SEL   0X0020
-#define PBC_BCTRL2_ATA_EN       0X0040
-#define PBC_BCTRL2_IRDA_SD      0X0080
-#define PBC_BCTRL2_IRDA_EN      0X0100
-#define PBC_BCTRL2_CCTL10       0X0200
-#define PBC_BCTRL2_CCTL11       0X0400
-
-/* PBC Board Control Register 3 bit definitions */
-#define PBC_BCTRL3_HSH_EN       0X0020
-#define PBC_BCTRL3_FSH_MOD      0X0040
-#define PBC_BCTRL3_OTG_HS_EN    0X0080
-#define PBC_BCTRL3_OTG_VBUS_EN  0X0100
-#define PBC_BCTRL3_FSH_VBUS_EN  0X0200
-#define PBC_BCTRL3_USB_OTG_ON   0X0800
-#define PBC_BCTRL3_USB_FSH_ON   0X1000
-
-/* PBC Board Control Register 4 bit definitions */
-#define PBC_BCTRL4_REGEN_SEL    0X0001
-#define PBC_BCTRL4_USER_OFF     0X0002
-#define PBC_BCTRL4_VIB_EN       0X0004
-#define PBC_BCTRL4_PWRGT1_EN    0X0008
-#define PBC_BCTRL4_PWRGT2_EN    0X0010
-#define PBC_BCTRL4_STDBY_PRI    0X0020
-
-#ifndef __ASSEMBLY__
-/*
- * Enumerations for SD cards and memory stick card. This corresponds to
- * the card EN bits in the IMR: SD1_EN | MS_EN | SD3_EN | SD2_EN.
- */
-enum mxc_card_no {
-       MXC_CARD_SD2 = 0,
-       MXC_CARD_SD3,
-       MXC_CARD_MS,
-       MXC_CARD_SD1,
-       MXC_CARD_MIN = MXC_CARD_SD2,
-       MXC_CARD_MAX = MXC_CARD_SD1,
-};
-#endif
-
-#define MXC_CPLD_VER_1_50       0x01
-
-/*
- * PBC BSTAT Register bit definitions
- */
-#define PBC_BSTAT_PRI_INT       0X0001
-#define PBC_BSTAT_USB_BYP       0X0002
-#define PBC_BSTAT_ATA_IOCS16    0X0004
-#define PBC_BSTAT_ATA_CBLID     0X0008
-#define PBC_BSTAT_ATA_DASP      0X0010
-#define PBC_BSTAT_PWR_RDY       0X0020
-#define PBC_BSTAT_SD3_WP        0X0100
-#define PBC_BSTAT_SD2_WP        0X0200
-#define PBC_BSTAT_SD1_WP        0X0400
-#define PBC_BSTAT_SD3_DET       0X0800
-#define PBC_BSTAT_SD2_DET       0X1000
-#define PBC_BSTAT_SD1_DET       0X2000
-#define PBC_BSTAT_MS_DET        0X4000
-#define PBC_BSTAT_SD3_DET_BIT   11
-#define PBC_BSTAT_SD2_DET_BIT   12
-#define PBC_BSTAT_SD1_DET_BIT   13
-#define PBC_BSTAT_MS_DET_BIT    14
-#define MXC_BSTAT_BIT(n)        ((n == MXC_CARD_SD2) ? PBC_BSTAT_SD2_DET : \
-                                ((n == MXC_CARD_SD3) ? PBC_BSTAT_SD3_DET : \
-                                ((n == MXC_CARD_SD1) ? PBC_BSTAT_SD1_DET : \
-                                ((n == MXC_CARD_MS) ? PBC_BSTAT_MS_DET : \
-                                       0x0))))
-
-/*
- * PBC UART Control Register bit definitions
- */
-#define PBC_UCTRL_DCE_DCD       0X0001
-#define PBC_UCTRL_DCE_DSR       0X0002
-#define PBC_UCTRL_DCE_RI        0X0004
-#define PBC_UCTRL_DTE_DTR       0X0100
-
-/*
- * PBC UART Status Register bit definitions
- */
-#define PBC_USTAT_DTE_DCD       0X0001
-#define PBC_USTAT_DTE_DSR       0X0002
-#define PBC_USTAT_DTE_RI        0X0004
-#define PBC_USTAT_DCE_DTR       0X0100
-
-/*
- * PBC Interupt mask register bit definitions
- */
-#define PBC_INTR_SD3_R_EN_BIT   4
-#define PBC_INTR_SD2_R_EN_BIT   0
-#define PBC_INTR_SD1_R_EN_BIT   6
-#define PBC_INTR_MS_R_EN_BIT    5
-#define PBC_INTR_SD3_EN_BIT     13
-#define PBC_INTR_SD2_EN_BIT     12
-#define PBC_INTR_MS_EN_BIT      14
-#define PBC_INTR_SD1_EN_BIT     15
-
-#define PBC_INTR_SD2_R_EN       0x0001
-#define PBC_INTR_LOW_BAT        0X0002
-#define PBC_INTR_OTG_FSOVER     0X0004
-#define PBC_INTR_FSH_OVER       0X0008
-#define PBC_INTR_SD3_R_EN       0x0010
-#define PBC_INTR_MS_R_EN        0x0020
-#define PBC_INTR_SD1_R_EN       0x0040
-#define PBC_INTR_FEC_INT        0X0080
-#define PBC_INTR_ENET_INT       0X0100
-#define PBC_INTR_OTGFS_INT      0X0200
-#define PBC_INTR_XUART_INT      0X0400
-#define PBC_INTR_CCTL12         0X0800
-#define PBC_INTR_SD2_EN         0x1000
-#define PBC_INTR_SD3_EN         0x2000
-#define PBC_INTR_MS_EN          0x4000
-#define PBC_INTR_SD1_EN         0x8000
-
-
-
-/* For interrupts like xuart, enet etc */
-#define EXPIO_PARENT_INT        IOMUX_TO_IRQ(MX27_PIN_TIN)
-#define MXC_MAX_EXP_IO_LINES    16
-
-/*
- * This corresponds to PBC_INTMASK_SET_REG at offset 0x38.
- *
- */
-#define EXPIO_INT_LOW_BAT       (MXC_EXP_IO_BASE + 1)
-#define EXPIO_INT_OTG_FS_OVR    (MXC_EXP_IO_BASE + 2)
-#define EXPIO_INT_FSH_OVR       (MXC_EXP_IO_BASE + 3)
-#define EXPIO_INT_RES4          (MXC_EXP_IO_BASE + 4)
-#define EXPIO_INT_RES5          (MXC_EXP_IO_BASE + 5)
-#define EXPIO_INT_RES6          (MXC_EXP_IO_BASE + 6)
-#define EXPIO_INT_FEC           (MXC_EXP_IO_BASE + 7)
-#define EXPIO_INT_ENET_INT      (MXC_EXP_IO_BASE + 8)
-#define EXPIO_INT_OTG_FS_INT    (MXC_EXP_IO_BASE + 9)
-#define EXPIO_INT_XUART_INTA    (MXC_EXP_IO_BASE + 10)
-#define EXPIO_INT_CCTL12_INT    (MXC_EXP_IO_BASE + 11)
-#define EXPIO_INT_SD2_EN        (MXC_EXP_IO_BASE + 12)
-#define EXPIO_INT_SD3_EN        (MXC_EXP_IO_BASE + 13)
-#define EXPIO_INT_MS_EN         (MXC_EXP_IO_BASE + 14)
-#define EXPIO_INT_SD1_EN        (MXC_EXP_IO_BASE + 15)
-
-/*
- * This is System IRQ used by CS8900A for interrupt generation
- * taken from platform.h
- */
-#define CS8900AIRQ              EXPIO_INT_ENET_INT
-/* This is I/O Base address used to access registers of CS8900A on MXC ADS */
-#define CS8900A_BASE_ADDRESS    (PBC_CS8900A_IOBASE_REG + 0x300)
-
-#define MXC_PMIC_INT_LINE       IOMUX_TO_IRQ(MX27_PIN_TOUT)
-
-/*
-* This is used to detect if the CPLD version is for mx27 evb board rev-a
-*/
-#define PBC_CPLD_VERSION_IS_REVA() \
-       ((__raw_readw(PBC_VERSION_REG) & \
-       (PBC_VERSION_ADS | PBC_VERSION_EVB_REVB))\
-       == 0)
-
-/* This is used to active or inactive ata signal in CPLD .
- *  It is dependent with hardware
- */
-#define PBC_ATA_SIGNAL_ACTIVE() \
-       __raw_writew(           \
-               PBC_BCTRL2_ATAFEC_EN|PBC_BCTRL2_ATAFEC_SEL|PBC_BCTRL2_ATA_EN, \
-               PBC_BCTRL2_CLEAR_REG)
-
-#define PBC_ATA_SIGNAL_INACTIVE() \
-       __raw_writew(  \
-               PBC_BCTRL2_ATAFEC_EN|PBC_BCTRL2_ATAFEC_SEL|PBC_BCTRL2_ATA_EN, \
-               PBC_BCTRL2_SET_REG)
-
-#define MXC_BD_LED1             (1 << 5)
-#define MXC_BD_LED2             (1 << 6)
-#define MXC_BD_LED_ON(led) \
-       __raw_writew(led, PBC_BCTRL1_SET_REG)
-#define MXC_BD_LED_OFF(led) \
-       __raw_writew(led, PBC_BCTRL1_CLEAR_REG)
-
-/* to determine the correct external crystal reference */
-#define CKIH_27MHZ_BIT_SET      (1 << 3)
-
-#endif                         /* __ASM_ARCH_MXC_BOARD_MX27ADS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27lite.h b/arch/arm/plat-mxc/include/mach/board-mx27lite.h
deleted file mode 100644 (file)
index ea87551..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 2009 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 __ASM_ARCH_MXC_BOARD_MX27LITE_H__
-#define __ASM_ARCH_MXC_BOARD_MX27LITE_H__
-
-#endif /* __ASM_ARCH_MXC_BOARD_MX27LITE_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27pdk.h b/arch/arm/plat-mxc/include/mach/board-mx27pdk.h
deleted file mode 100644 (file)
index fec1bcf..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 2009 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 __ASM_ARCH_MXC_BOARD_MX27PDK_H__
-#define __ASM_ARCH_MXC_BOARD_MX27PDK_H__
-
-#endif /* __ASM_ARCH_MXC_BOARD_MX27PDK_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31_3ds.h b/arch/arm/plat-mxc/include/mach/board-mx31_3ds.h
deleted file mode 100644 (file)
index da92933..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2008 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 __ASM_ARCH_MXC_BOARD_MX31_3DS_H__
-#define __ASM_ARCH_MXC_BOARD_MX31_3DS_H__
-
-/* Definitions for components on the Debug board */
-
-/* Base address of CPLD controller on the Debug board */
-#define DEBUG_BASE_ADDRESS             CS5_IO_ADDRESS(CS5_BASE_ADDR)
-
-/* LAN9217 ethernet base address */
-#define LAN9217_BASE_ADDR              CS5_BASE_ADDR
-
-/* CPLD config and interrupt base address */
-#define CPLD_ADDR                      (DEBUG_BASE_ADDRESS + 0x20000)
-
-/* LED switchs */
-#define CPLD_LED_REG                   (CPLD_ADDR + 0x00)
-/* buttons */
-#define CPLD_SWITCH_BUTTONS_REG        (EXPIO_ADDR + 0x08)
-/* status, interrupt */
-#define CPLD_INT_STATUS_REG            (CPLD_ADDR + 0x10)
-#define CPLD_INT_MASK_REG              (CPLD_ADDR + 0x38)
-#define CPLD_INT_RESET_REG             (CPLD_ADDR + 0x20)
-/* magic word for debug CPLD */
-#define CPLD_MAGIC_NUMBER1_REG         (CPLD_ADDR + 0x40)
-#define CPLD_MAGIC_NUMBER2_REG         (CPLD_ADDR + 0x48)
-/* CPLD code version */
-#define CPLD_CODE_VER_REG              (CPLD_ADDR + 0x50)
-/* magic word for debug CPLD */
-#define CPLD_MAGIC_NUMBER3_REG         (CPLD_ADDR + 0x58)
-/* module reset register */
-#define CPLD_MODULE_RESET_REG          (CPLD_ADDR + 0x60)
-/* CPU ID and Personality ID */
-#define CPLD_MCU_BOARD_ID_REG          (CPLD_ADDR + 0x68)
-
-/* CPLD IRQ line for external uart, external ethernet etc */
-#define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
-
-#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
-#define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
-
-#define EXPIO_INT_ENET         (MXC_EXP_IO_BASE + 0)
-#define EXPIO_INT_XUART_A      (MXC_EXP_IO_BASE + 1)
-#define EXPIO_INT_XUART_B      (MXC_EXP_IO_BASE + 2)
-#define EXPIO_INT_BUTTON_A     (MXC_EXP_IO_BASE + 3)
-#define EXPIO_INT_BUTTON_B     (MXC_EXP_IO_BASE + 4)
-
-#define MXC_MAX_EXP_IO_LINES   16
-
-#endif /* __ASM_ARCH_MXC_BOARD_MX31_3DS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
deleted file mode 100644 (file)
index 095a199..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2005-2007 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 __ASM_ARCH_MXC_BOARD_MX31ADS_H__
-#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
-
-#include <mach/hardware.h>
-
-/* Base address of PBC controller */
-#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
-/* Offsets for the PBC Controller register */
-
-/* PBC Board status register offset */
-#define PBC_BSTAT               0x000002
-
-/* PBC Board control register 1 set address */
-#define PBC_BCTRL1_SET          0x000004
-
-/* PBC Board control register 1 clear address */
-#define PBC_BCTRL1_CLEAR        0x000006
-
-/* PBC Board control register 2 set address */
-#define PBC_BCTRL2_SET          0x000008
-
-/* PBC Board control register 2 clear address */
-#define PBC_BCTRL2_CLEAR        0x00000A
-
-/* PBC Board control register 3 set address */
-#define PBC_BCTRL3_SET          0x00000C
-
-/* PBC Board control register 3 clear address */
-#define PBC_BCTRL3_CLEAR        0x00000E
-
-/* PBC Board control register 4 set address */
-#define PBC_BCTRL4_SET          0x000010
-
-/* PBC Board control register 4 clear address */
-#define PBC_BCTRL4_CLEAR        0x000012
-
-/* PBC Board status register 1 */
-#define PBC_BSTAT1              0x000014
-
-/* PBC Board interrupt status register */
-#define PBC_INTSTATUS           0x000016
-
-/* PBC Board interrupt current status register */
-#define PBC_INTCURR_STATUS      0x000018
-
-/* PBC Interrupt mask register set address */
-#define PBC_INTMASK_SET         0x00001A
-
-/* PBC Interrupt mask register clear address */
-#define PBC_INTMASK_CLEAR       0x00001C
-
-/* External UART A */
-#define PBC_SC16C652_UARTA      0x010000
-
-/* External UART B */
-#define PBC_SC16C652_UARTB      0x010010
-
-/* Ethernet Controller IO base address */
-#define PBC_CS8900A_IOBASE      0x020000
-
-/* Ethernet Controller Memory base address */
-#define PBC_CS8900A_MEMBASE     0x021000
-
-/* Ethernet Controller DMA base address */
-#define PBC_CS8900A_DMABASE     0x022000
-
-/* External chip select 0 */
-#define PBC_XCS0                0x040000
-
-/* LCD Display enable */
-#define PBC_LCD_EN_B            0x060000
-
-/* Code test debug enable */
-#define PBC_CODE_B              0x070000
-
-/* PSRAM memory select */
-#define PBC_PSRAM_B             0x5000000
-
-#define PBC_INTSTATUS_REG      (PBC_INTSTATUS + PBC_BASE_ADDRESS)
-#define PBC_INTCURR_STATUS_REG (PBC_INTCURR_STATUS + PBC_BASE_ADDRESS)
-#define PBC_INTMASK_SET_REG    (PBC_INTMASK_SET + PBC_BASE_ADDRESS)
-#define PBC_INTMASK_CLEAR_REG  (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
-#define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
-
-#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
-#define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
-
-#define EXPIO_INT_LOW_BAT      (MXC_EXP_IO_BASE + 0)
-#define EXPIO_INT_PB_IRQ       (MXC_EXP_IO_BASE + 1)
-#define EXPIO_INT_OTG_FS_OVR   (MXC_EXP_IO_BASE + 2)
-#define EXPIO_INT_FSH_OVR      (MXC_EXP_IO_BASE + 3)
-#define EXPIO_INT_RES4         (MXC_EXP_IO_BASE + 4)
-#define EXPIO_INT_RES5         (MXC_EXP_IO_BASE + 5)
-#define EXPIO_INT_RES6         (MXC_EXP_IO_BASE + 6)
-#define EXPIO_INT_RES7         (MXC_EXP_IO_BASE + 7)
-#define EXPIO_INT_ENET_INT     (MXC_EXP_IO_BASE + 8)
-#define EXPIO_INT_OTG_FS_INT   (MXC_EXP_IO_BASE + 9)
-#define EXPIO_INT_XUART_INTA   (MXC_EXP_IO_BASE + 10)
-#define EXPIO_INT_XUART_INTB   (MXC_EXP_IO_BASE + 11)
-#define EXPIO_INT_SYNTH_IRQ    (MXC_EXP_IO_BASE + 12)
-#define EXPIO_INT_CE_INT1      (MXC_EXP_IO_BASE + 13)
-#define EXPIO_INT_CE_INT2      (MXC_EXP_IO_BASE + 14)
-#define EXPIO_INT_RES15                (MXC_EXP_IO_BASE + 15)
-
-#define MXC_MAX_EXP_IO_LINES   16
-
-#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
index eb5a5024622efbe9da16228e44b338b51037f559..0df71bfefbb10819883de74f5bae623227b0d7f5 100644 (file)
@@ -31,7 +31,7 @@ enum mx31lilly_boards {
 
 /*
  * This CPU module needs a baseboard to work. After basic initializing
- * its own devices, it calls baseboard's init function.
+ * its own devices, it calls the baseboard's init function.
  */
 
 extern void mx31lilly_db_init(void);
index 2b2da0367578dbb13a4dbf6e12894709f079acec..c1ad0ae807cc57ee20cbddd3cb8021efe61196c6 100644 (file)
@@ -32,7 +32,7 @@ enum mx31lite_boards {
 
 /*
  * This CPU module needs a baseboard to work. After basic initializing
- * its own devices, it calls baseboard's init function.
+ * its own devices, it calls the baseboard's init function.
  */
 
 extern void mx31lite_db_init(void);
index 36ff3cedee1a1d3cd3d7ffbc1c32ab185ed1cdcf..de14543891cf4b40ff569fbc7a889170fdbb5c7f 100644 (file)
@@ -31,7 +31,7 @@ enum mx31moboard_boards {
 
 /*
  * This CPU module needs a baseboard to work. After basic initializing
- * its own devices, it calls baseboard's init function.
+ * its own devices, it calls the baseboard's init function.
  */
 
 extern void mx31moboard_devboard_init(void);
index 410f9786ed2292d7c909ddd2b690a8d7cbf83c51..6f371e35753dfbb557840a0307a931685615563a 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __ASSEMBLY__
 /*
  * This CPU module needs a baseboard to work. After basic initializing
- * its own devices, it calls baseboard's init function.
+ * its own devices, it calls the baseboard's init function.
  * TODO: Add your own baseboard init function and call it from
  * inside pcm038_init().
  *
diff --git a/arch/arm/plat-mxc/include/mach/board-qong.h b/arch/arm/plat-mxc/include/mach/board-qong.h
deleted file mode 100644 (file)
index 6d88c7a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.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 __ASM_ARCH_MXC_BOARD_QONG_H__
-#define __ASM_ARCH_MXC_BOARD_QONG_H__
-
-/* NOR FLASH */
-#define QONG_NOR_SIZE          (128*1024*1024)
-
-#endif /* __ASM_ARCH_MXC_BOARD_QONG_H__ */
index 0b6e11eaeb8ca0b2d64c847810a44fbc96355909..25606409aabcfb7de02a3dbce55e7221b68d2ece 100644 (file)
@@ -23,8 +23,8 @@
 #error "CONFIG_DEBUG_LL is incompatible with multiple archs"
 #endif
 #include <mach/mx25.h>
-#define UART_PADDR     UART1_BASE_ADDR
-#define UART_VADDR     MX25_AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+#define UART_PADDR     MX25_UART1_BASE_ADDR
+#define UART_VADDR     MX25_AIPS1_IO_ADDRESS(MX25_UART1_BASE_ADDR)
 #endif
 
 #ifdef CONFIG_ARCH_MX2
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
new file mode 100644 (file)
index 0000000..c5f68c5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+
+struct platform_device *imx_add_platform_device(const char *name, int id,
+               const struct resource *res, unsigned int num_resources,
+               const void *data, size_t size_data);
+
+#if defined (CONFIG_CAN_FLEXCAN) || defined (CONFIG_CAN_FLEXCAN_MODULE)
+#include <linux/can/platform/flexcan.h>
+struct platform_device *__init imx_add_flexcan(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irq,
+               const struct flexcan_platform_data *pdata);
+#else
+/* the ifdef can be removed once the flexcan driver has been merged */
+struct flexcan_platform_data;
+static inline struct platform_device *__init imx_add_flexcan(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irq,
+               const struct flexcan_platform_data *pdata)
+{
+       return NULL;
+}
+#endif
+
+#include <mach/i2c.h>
+struct platform_device *__init imx_add_imx_i2c(int id,
+               resource_size_t iobase, resource_size_t iosize, int irq,
+               const struct imxi2c_platform_data *pdata);
+
+#include <mach/imx-uart.h>
+struct platform_device *__init imx_add_imx_uart_3irq(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irqrx, resource_size_t irqtx,
+               resource_size_t irqrts,
+               const struct imxuart_platform_data *pdata);
+struct platform_device *__init imx_add_imx_uart_1irq(int id,
+               resource_size_t iobase, resource_size_t iosize,
+               resource_size_t irq,
+               const struct imxuart_platform_data *pdata);
+
+#include <mach/mxc_nand.h>
+struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
+               int irq, const struct mxc_nand_platform_data *pdata);
+struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
+               int irq, const struct mxc_nand_platform_data *pdata);
+
+#include <mach/spi.h>
+struct platform_device *__init imx_add_spi_imx(int id,
+               resource_size_t iobase, resource_size_t iosize, int irq,
+               const struct spi_imx_master *pdata);
similarity index 64%
rename from arch/arm/plat-mxc/include/mach/board-eukrea_cpuimx27.h
rename to arch/arm/plat-mxc/include/mach/eukrea-baseboards.h
index a1fd5830af484758c21c70d453b595746f063091..634e3f4c454df222728aa678bdcd657967286dbc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Eric Benard - eric@eukrea.com
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
  *
  * Based on board-pcm038.h which is :
  * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
  * MA 02110-1301, USA.
  */
 
-#ifndef __ASM_ARCH_MXC_BOARD_EUKREA_CPUIMX27_H__
-#define __ASM_ARCH_MXC_BOARD_EUKREA_CPUIMX27_H__
+#ifndef __MACH_EUKREA_BASEBOARDS_H__
+#define __MACH_EUKREA_BASEBOARDS_H__
 
 #ifndef __ASSEMBLY__
 /*
  * This CPU module needs a baseboard to work. After basic initializing
  * its own devices, it calls baseboard's init function.
  * TODO: Add your own baseboard init function and call it from
- * inside eukrea_cpuimx27_init().
+ * inside eukrea_cpuimx25_init() eukrea_cpuimx27_init()
+ * eukrea_cpuimx35_init() or eukrea_cpuimx51_init().
  *
  * This example here is for the development board. Refer
- * eukrea_mbimx27-baseboard.c
+ * mach-mx25/eukrea_mbimxsd-baseboard.c for cpuimx25
+ * mach-imx/eukrea_mbimx27-baseboard.c for cpuimx27
+ * mach-mx3/eukrea_mbimxsd-baseboard.c for cpuimx35
+ * mach-mx5/eukrea_mbimx51-baseboard.c for cpuimx51
  */
 
+extern void eukrea_mbimx25_baseboard_init(void);
 extern void eukrea_mbimx27_baseboard_init(void);
+extern void eukrea_mbimx35_baseboard_init(void);
+extern void eukrea_mbimx51_baseboard_init(void);
 
 #endif
 
-#endif /* __ASM_ARCH_MXC_BOARD_EUKREA_CPUIMX27_H__ */
+#endif /* __MACH_EUKREA_BASEBOARDS_H__ */
index 894d2f87c85600c495d117a6d0f524060ee15aaa..661fbc6057597c2bec30545af8904396ad4d4328 100644 (file)
 struct mxc_gpio_port {
        void __iomem *base;
        int irq;
+       int irq_high;
        int virtual_irq_start;
        struct gpio_chip chip;
        u32 both_edges;
+       spinlock_t lock;
 };
 
 int mxc_gpio_init(struct mxc_gpio_port*, int);
index f39220d1b67af1112a31ab72f713f0c45153df6d..d7f52c91f82edb09f5aa686abdae16b6ce78963b 100644 (file)
 #define MX25_PAD_OE_ACD__GPIO_1_25     IOMUX_PAD(0x30c, 0x114, 0x15, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_CONTRAST__CONTRAST    IOMUX_PAD(0x310, 0x118, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_CONTRAST__PWM4_PWMO   IOMUX_PAD(0x310, 0x118, 0x14, 0, 0, NO_PAD_CTRL)
 #define MX25_PAD_CONTRAST__FEC_CRS     IOMUX_PAD(0x310, 0x118, 0x15, 0x508, 1, NO_PAD_CTRL)
 
 #define MX25_PAD_PWM__PWM              IOMUX_PAD(0x314, 0x11c, 0x10, 0, 0, NO_PAD_CTRL)
 #define MX25_PAD_SD1_DATA3__FEC_CRS    IOMUX_PAD(0x39c, 0x1a4, 0x10, 0x508, 2, NO_PAD_CTRL)
 #define MX25_PAD_SD1_DATA3__GPIO_2_28  IOMUX_PAD(0x39c, 0x1a4, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_ROW0__KPP_ROW0    IOMUX_PAD(0x3a0, 0x1a8, 0x10, 0, 0, PAD_CTL_PKE)
+#define KPP_CTL_ROW    (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
+#define KPP_CTL_COL    (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP | PAD_CTL_ODE)
+
+#define MX25_PAD_KPP_ROW0__KPP_ROW0    IOMUX_PAD(0x3a0, 0x1a8, 0x10, 0, 0, KPP_CTL_ROW)
 #define MX25_PAD_KPP_ROW0__GPIO_2_29   IOMUX_PAD(0x3a0, 0x1a8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_ROW1__KPP_ROW1    IOMUX_PAD(0x3a4, 0x1ac, 0x10, 0, 0, PAD_CTL_PKE)
+#define MX25_PAD_KPP_ROW1__KPP_ROW1    IOMUX_PAD(0x3a4, 0x1ac, 0x10, 0, 0, KPP_CTL_ROW)
 #define MX25_PAD_KPP_ROW1__GPIO_2_30   IOMUX_PAD(0x3a4, 0x1ac, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_ROW2__KPP_ROW2    IOMUX_PAD(0x3a8, 0x1b0, 0x10, 0, 0, PAD_CTL_PKE)
+#define MX25_PAD_KPP_ROW2__KPP_ROW2    IOMUX_PAD(0x3a8, 0x1b0, 0x10, 0, 0, KPP_CTL_ROW)
 #define MX25_PAD_KPP_ROW2__CSI_D0      IOMUX_PAD(0x3a8, 0x1b0, 0x13, 0x488, 2, NO_PAD_CTRL)
 #define MX25_PAD_KPP_ROW2__GPIO_2_31   IOMUX_PAD(0x3a8, 0x1b0, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_ROW3__KPP_ROW3    IOMUX_PAD(0x3ac, 0x1b4, 0x10, 0, 0, PAD_CTL_PKE)
+#define MX25_PAD_KPP_ROW3__KPP_ROW3    IOMUX_PAD(0x3ac, 0x1b4, 0x10, 0, 0, KPP_CTL_ROW)
 #define MX25_PAD_KPP_ROW3__CSI_LD1     IOMUX_PAD(0x3ac, 0x1b4, 0x13, 0x48c, 2, NO_PAD_CTRL)
 #define MX25_PAD_KPP_ROW3__GPIO_3_0    IOMUX_PAD(0x3ac, 0x1b4, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_COL0__KPP_COL0    IOMUX_PAD(0x3b0, 0x1b8, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL0__KPP_COL0    IOMUX_PAD(0x3b0, 0x1b8, 0x10, 0, 0, KPP_CTL_COL)
+#define MX25_PAD_KPP_COL0__UART4_RXD_MUX IOMUX_PAD(0x3b0, 0x1b8, 0x11, 0x570, 1, NO_PAD_CTRL)
+#define MX25_PAD_KPP_COL0__AUD5_TXD    IOMUX_PAD(0x3b0, 0x1b8, 0x12, 0, 0, PAD_CTL_PKE | PAD_CTL_PUS_100K_UP)
 #define MX25_PAD_KPP_COL0__GPIO_3_1    IOMUX_PAD(0x3b0, 0x1b8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_COL1__KPP_COL1    IOMUX_PAD(0x3b4, 0x1bc, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL1__KPP_COL1    IOMUX_PAD(0x3b4, 0x1bc, 0x10, 0, 0, KPP_CTL_COL)
+#define MX25_PAD_KPP_COL1__UART4_TXD_MUX IOMUX_PAD(0x3b4, 0x1bc, 0x11, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_KPP_COL1__AUD5_RXD    IOMUX_PAD(0x3b4, 0x1bc, 0x12, 0, 0, PAD_CTL_PKE | PAD_CTL_PUS_100K_UP)
 #define MX25_PAD_KPP_COL1__GPIO_3_2    IOMUX_PAD(0x3b4, 0x1bc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_COL2__KPP_COL2    IOMUX_PAD(0x3b8, 0x1c0, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL2__KPP_COL2    IOMUX_PAD(0x3b8, 0x1c0, 0x10, 0, 0, KPP_CTL_COL)
+#define MX25_PAD_KPP_COL2__UART4_RTS   IOMUX_PAD(0x3b8, 0x1c0, 0x11, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_KPP_COL2__AUD5_TXC    IOMUX_PAD(0x3b8, 0x1c0, 0x12, 0, 0, PAD_CTL_PKE | PAD_CTL_PUS_100K_UP)
 #define MX25_PAD_KPP_COL2__GPIO_3_3    IOMUX_PAD(0x3b8, 0x1c0, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_KPP_COL3__KPP_COL3    IOMUX_PAD(0x3bc, 0x1c4, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL3__KPP_COL3    IOMUX_PAD(0x3bc, 0x1c4, 0x10, 0, 0, KPP_CTL_COL)
+#define MX25_PAD_KPP_COL3__UART4_CTS   IOMUX_PAD(0x3bc, 0x1c4, 0x11, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_KPP_COL3__AUD5_TXFS   IOMUX_PAD(0x3bc, 0x1c4, 0x12, 0, 0, PAD_CTL_PKE | PAD_CTL_PUS_100K_UP)
 #define MX25_PAD_KPP_COL3__GPIO_3_4    IOMUX_PAD(0x3bc, 0x1c4, 0x15, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_FEC_MDC__FEC_MDC      IOMUX_PAD(0x3c0, 0x1c8, 0x10, 0, 0, NO_PAD_CTRL)
index ab0f95d953d02539ab76e69973056814a79ffcd4..21bfa46785bb5254e16ed1cfd8f36d7e384dbfcc 100644 (file)
@@ -27,8 +27,8 @@ typedef enum iomux_config {
        IOMUX_CONFIG_ALT5,
        IOMUX_CONFIG_ALT6,
        IOMUX_CONFIG_ALT7,
-       IOMUX_CONFIG_GPIO,      /* added to help user use GPIO mode */
-       IOMUX_CONFIG_SION = 0x1 << 4,   /* LOOPBACK:MUX SION bit */
+       IOMUX_CONFIG_GPIO,      /* added to help user use GPIO mode */
+       IOMUX_CONFIG_SION = 0x1 << 4,   /* LOOPBACK:MUX SION bit */
 } iomux_pin_cfg_t;
 
 /* Pad control groupings */
@@ -38,6 +38,8 @@ typedef enum iomux_config {
                                PAD_CTL_SRE_FAST)
 #define MX51_UART3_PAD_CTRL    (PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \
                                PAD_CTL_SRE_FAST)
+#define MX51_I2C_PAD_CTRL      (PAD_CTL_SRE_FAST | PAD_CTL_ODE | \
+                               PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP | PAD_CTL_HYS)
 #define MX51_USBH1_PAD_CTRL    (PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \
                                PAD_CTL_PUS_100K_UP | PAD_CTL_PUE | \
                                PAD_CTL_PKE | PAD_CTL_HYS)
@@ -46,289 +48,278 @@ typedef enum iomux_config {
 
 /*
  * The naming convention for the pad modes is MX51_PAD_<padname>__<padmode>
- * If <padname> or <padmode> refers to a GPIO, it is named
- * GPIO_<unit>_<num> see also iomux-v3.h
+ * If <padname> or <padmode> refers to a GPIO, it is named GPIO_<unit>_<num>
+ * See also iomux-v3.h
  */
 
-/*
- * FIXME: This was converted using scripts from existing Freescale code to
- * this form used upstream. Need to verify the name format.
- */
-
-/*                                             PAD      MUX   ALT INPSE PATH PADCTRL */
-
-#define MX51_PAD_GPIO_2_0__EIM_D16     IOMUX_PAD(0x3f0, 0x05c, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_1__EIM_D17     IOMUX_PAD(0x3f4, 0x060, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_2__EIM_D18     IOMUX_PAD(0x3f8, 0x064, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_3__EIM_D19     IOMUX_PAD(0x3fc, 0x068, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_4__EIM_D20     IOMUX_PAD(0x400, 0x06c, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_5__EIM_D21     IOMUX_PAD(0x404, 0x070, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_D21__GPIO_2_5     IOMUX_PAD(0x404, 0x070, IOMUX_CONFIG_ALT1, 0x0,   0, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_6__EIM_D22     IOMUX_PAD(0x408, 0x074, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_7__EIM_D23     IOMUX_PAD(0x40c, 0x078, 1, 0x0,   0, NO_PAD_CTRL)
-
-/* Babbage UART3 */
-#define MX51_PAD_EIM_D24__UART3_CTS    IOMUX_PAD(0x410, 0x07c, IOMUX_CONFIG_ALT3, 0x0, 0, MX51_UART3_PAD_CTRL)
-#define MX51_PAD_EIM_D25__UART3_RXD    IOMUX_PAD(0x414, 0x080, IOMUX_CONFIG_ALT3, 0x9f4, 0, MX51_UART3_PAD_CTRL)
-#define MX51_PAD_EIM_D26__UART3_TXD    IOMUX_PAD(0x418, 0x084, IOMUX_CONFIG_ALT3, 0x0, 0, MX51_UART3_PAD_CTRL)
-#define MX51_PAD_EIM_D27__UART3_RTS    IOMUX_PAD(0x41c, 0x088, IOMUX_CONFIG_ALT3, 0x9f0, 0, MX51_UART3_PAD_CTRL)
-
-#define MX51_PAD_EIM_D28__EIM_D28      IOMUX_PAD(0x420, 0x08c, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_D29__EIM_D29      IOMUX_PAD(0x424, 0x090, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_D30__EIM_D30      IOMUX_PAD(0x428, 0x094, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_D31__EIM_D31      IOMUX_PAD(0x42c, 0x09c, 0, 0x0,   0, NO_PAD_CTRL)
-
-#define MX51_PAD_GPIO_2_10__EIM_A16    IOMUX_PAD(0x430, 0x09c, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_11__EIM_A17    IOMUX_PAD(0x434, 0x0a0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_12__EIM_A18    IOMUX_PAD(0x438, 0x0a4, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_13__EIM_A19    IOMUX_PAD(0x43c, 0x0a8, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_14__EIM_A20    IOMUX_PAD(0x440, 0x0ac, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_15__EIM_A21    IOMUX_PAD(0x444, 0x0b0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_16__EIM_A22    IOMUX_PAD(0x448, 0x0b4, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_17__EIM_A23    IOMUX_PAD(0x44c, 0x0b8, 1, 0x0,   0, NO_PAD_CTRL)
-
-#define MX51_PAD_GPIO_2_18__EIM_A24    IOMUX_PAD(0x450, 0x0bc, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_19__EIM_A25    IOMUX_PAD(0x454, 0x0c0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_20__EIM_A26    IOMUX_PAD(0x458, 0x0c4, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_21__EIM_A27    IOMUX_PAD(0x45c, 0x0c8, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_EB0__EIM_EB0      IOMUX_PAD(0x460, 0x0cc, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_EB1__EIM_EB1      IOMUX_PAD(0x464, 0x0d0, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_22__EIM_EB2    IOMUX_PAD(0x468, 0x0d4, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_23__EIM_EB3    IOMUX_PAD(0x46c, 0x0d8, 1, 0x0,   0, NO_PAD_CTRL)
-
-#define MX51_PAD_GPIO_2_24__EIM_OE     IOMUX_PAD(0x470, 0x0dc, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_25__EIM_CS0    IOMUX_PAD(0x474, 0x0e0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_26__EIM_CS1    IOMUX_PAD(0x478, 0x0e4, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_27__EIM_CS2    IOMUX_PAD(0x47c, 0x0e8, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_28__EIM_CS3    IOMUX_PAD(0x480, 0x0ec, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_29__EIM_CS4    IOMUX_PAD(0x484, 0x0f0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_30__EIM_CS5    IOMUX_PAD(0x488, 0x0f4, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_31__EIM_DTACK  IOMUX_PAD(0x48c, 0x0f8, 1, 0x0,   0, NO_PAD_CTRL)
-
-#define MX51_PAD_GPIO_3_1__EIM_LBA     IOMUX_PAD(0x494, 0xFC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_2__EIM_CRE     IOMUX_PAD(0x4A0, 0x100, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DRAM_CS1__DRAM_CS1    IOMUX_PAD(0x4D0, 0x104, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_3__NANDF_WE_B  IOMUX_PAD(0x4E4, 0x108, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_4__NANDF_RE_B  IOMUX_PAD(0x4E8, 0x10C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_5__NANDF_ALE   IOMUX_PAD(0x4EC, 0x110, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_6__NANDF_CLE   IOMUX_PAD(0x4F0, 0x114, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_7__NANDF_WP_B  IOMUX_PAD(0x4F4, 0x118, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_8__NANDF_RB0   IOMUX_PAD(0x4F8, 0x11C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_9__NANDF_RB1   IOMUX_PAD(0x4FC, 0x120, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_10__NANDF_RB2  IOMUX_PAD(0x500, 0x124, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_11__NANDF_RB3  IOMUX_PAD(0x504, 0x128, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_12__GPIO_NAND  IOMUX_PAD(0x514, 0x12C, 3, 0x0, 0, NO_PAD_CTRL)
-/* REVISIT: Not sure of these values
-
-  #define MX51_PAD_GPIO_1___NANDF_RB4  IOMUX_PAD(, , , 0x0, 0, NO_PAD_CTRL)
-  #define MX51_PAD_GPIO_3_13__NANDF_RB5        IOMUX_PAD(0x5D8, 0x130, 3, 0x0, 0, NO_PAD_CTRL)
-  #define MX51_PAD_GPIO_3_15__NANDF_RB7        IOMUX_PAD(0x5E0, 0x138, 3, 0x0, 0, NO_PAD_CTRL)
-*/
-#define MX51_PAD_GPIO_3_14__NANDF_RB6  IOMUX_PAD(0x5DC, 0x134, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_16__NANDF_CS0  IOMUX_PAD(0x518, 0x130, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_17__NANDF_CS1  IOMUX_PAD(0x51C, 0x134, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_18__NANDF_CS2  IOMUX_PAD(0x520, 0x138, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_19__NANDF_CS3  IOMUX_PAD(0x524, 0x13C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_20__NANDF_CS4  IOMUX_PAD(0x528, 0x140, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_21__NANDF_CS5  IOMUX_PAD(0x52C, 0x144, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_22__NANDF_CS6  IOMUX_PAD(0x530, 0x148, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_23__NANDF_CS7  IOMUX_PAD(0x534, 0x14C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_24__NANDF_RDY_INT      IOMUX_PAD(0x538, 0x150, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_25__NANDF_D15  IOMUX_PAD(0x53C, 0x154, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_26__NANDF_D14  IOMUX_PAD(0x540, 0x158, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_27__NANDF_D13  IOMUX_PAD(0x544, 0x15C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_28__NANDF_D12  IOMUX_PAD(0x548, 0x160, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_29__NANDF_D11  IOMUX_PAD(0x54C, 0x164, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_30__NANDF_D10  IOMUX_PAD(0x550, 0x168, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_31__NANDF_D9   IOMUX_PAD(0x554, 0x16C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_0__NANDF_D8    IOMUX_PAD(0x558, 0x170, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_1__NANDF_D7    IOMUX_PAD(0x55C, 0x174, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_2__NANDF_D6    IOMUX_PAD(0x560, 0x178, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_3__NANDF_D5    IOMUX_PAD(0x564, 0x17C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_4__NANDF_D4    IOMUX_PAD(0x568, 0x180, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_5__NANDF_D3    IOMUX_PAD(0x56C, 0x184, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_6__NANDF_D2    IOMUX_PAD(0x570, 0x188, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_7__NANDF_D1    IOMUX_PAD(0x574, 0x18C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_8__NANDF_D0    IOMUX_PAD(0x578, 0x190, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_12__CSI1_D8    IOMUX_PAD(0x57C, 0x194, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_13__CSI1_D9    IOMUX_PAD(0x580, 0x198, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D10__CSI1_D10    IOMUX_PAD(0x584, 0x19C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D11__CSI1_D11    IOMUX_PAD(0x588, 0x1A0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D12__CSI1_D12    IOMUX_PAD(0x58C, 0x1A4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D13__CSI1_D13    IOMUX_PAD(0x590, 0x1A8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D14__CSI1_D14    IOMUX_PAD(0x594, 0x1AC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D15__CSI1_D15    IOMUX_PAD(0x598, 0x1B0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D16__CSI1_D16    IOMUX_PAD(0x59C, 0x1B4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D17__CSI1_D17    IOMUX_PAD(0x5A0, 0x1B8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D18__CSI1_D18    IOMUX_PAD(0x5A4, 0x1BC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_D19__CSI1_D19    IOMUX_PAD(0x5A8, 0x1C0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_VSYNC__CSI1_VSYNC        IOMUX_PAD(0x5AC, 0x1C4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_HSYNC__CSI1_HSYNC        IOMUX_PAD(0x5B0, 0x1C8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_PIXCLK__CSI1_PIXCLK      IOMUX_PAD(0x5B4, 0x0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_MCLK__CSI1_MCLK  IOMUX_PAD(0x5B8, 0x0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI1_PKE0__CSI1_PKE0  IOMUX_PAD(0x860, 0x0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_9__CSI2_D12    IOMUX_PAD(0x5BC, 0x1CC, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_10__CSI2_D13   IOMUX_PAD(0x5C0, 0x1D0, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_11__CSI2_D14   IOMUX_PAD(0x5C4, 0x1D4, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_12__CSI2_D15   IOMUX_PAD(0x5C8, 0x1D8, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_11__CSI2_D16   IOMUX_PAD(0x5CC, 0x1DC, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_12__CSI2_D17   IOMUX_PAD(0x5D0, 0x1E0, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_11__CSI2_D18   IOMUX_PAD(0x5D4, 0x1E4, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_12__CSI2_D19   IOMUX_PAD(0x5D8, 0x1E8, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_13__CSI2_VSYNC IOMUX_PAD(0x5DC, 0x1EC, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_14__CSI2_HSYNC IOMUX_PAD(0x5E0, 0x1F0, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_15__CSI2_PIXCLK        IOMUX_PAD(0x5E4, 0x1F4, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_CSI2_PKE0__CSI2_PKE0  IOMUX_PAD(0x81C, 0x0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_16__I2C1_CLK   IOMUX_PAD(0x5E8, 0x1F8, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_17__I2C1_DAT   IOMUX_PAD(0x5EC, 0x1FC, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_18__AUD3_BB_TXD        IOMUX_PAD(0x5F0, 0x200, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_19__AUD3_BB_RXD        IOMUX_PAD(0x5F4, 0x204, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_20__AUD3_BB_CK IOMUX_PAD(0x5F8, 0x208, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_21__AUD3_BB_FS IOMUX_PAD(0x5FC, 0x20C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_22__CSPI1_MOSI IOMUX_PAD(0x600, 0x210, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_23__CSPI1_MISO IOMUX_PAD(0x604, 0x214, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_24__CSPI1_SS0  IOMUX_PAD(0x608, 0x218, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_25__CSPI1_SS1  IOMUX_PAD(0x60C, 0x21C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_26__CSPI1_RDY  IOMUX_PAD(0x610, 0x220, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_27__CSPI1_SCLK IOMUX_PAD(0x614, 0x224, 3, 0x0, 0, NO_PAD_CTRL)
-
-/* Babbage UART1 */
-#define MX51_PAD_UART1_RXD__UART1_RXD  IOMUX_PAD(0x618, 0x228, IOMUX_CONFIG_ALT0, 0x9e4, 0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
-#define MX51_PAD_UART1_TXD__UART1_TXD  IOMUX_PAD(0x61C, 0x22C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
-#define MX51_PAD_UART1_RTS__UART1_RTS  IOMUX_PAD(0x620, 0x230, IOMUX_CONFIG_ALT0, 0x9e0, 0, MX51_UART1_PAD_CTRL)
-#define MX51_PAD_UART1_CTS__UART1_CTS  IOMUX_PAD(0x624, 0x234, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_UART1_PAD_CTRL)
-
-/* Babbage UART2 */
-#define MX51_PAD_UART2_RXD__UART2_RXD  IOMUX_PAD(0x628, 0x238, IOMUX_CONFIG_ALT0, 0x9ec, 2, MX51_UART2_PAD_CTRL)
-#define MX51_PAD_UART2_TXD__UART2_TXD  IOMUX_PAD(0x62C, 0x23C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_UART2_PAD_CTRL)
-
-#define MX51_PAD_GPIO_1_22__UART3_RXD  IOMUX_PAD(0x630, 0x240, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_23__UART3_TXD  IOMUX_PAD(0x634, 0x244, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_24__OWIRE_LINE IOMUX_PAD(0x638, 0x248, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_ROW0__KEY_ROW0    IOMUX_PAD(0x63C, 0x24C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_ROW1__KEY_ROW1    IOMUX_PAD(0x640, 0x250, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_ROW2__KEY_ROW2    IOMUX_PAD(0x644, 0x254, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_ROW3__KEY_ROW3    IOMUX_PAD(0x648, 0x258, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL0__KEY_COL0    IOMUX_PAD(0x64C, 0x25C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL1__KEY_COL1    IOMUX_PAD(0x650, 0x260, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL2__KEY_COL2    IOMUX_PAD(0x654, 0x264, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL3__KEY_COL3    IOMUX_PAD(0x658, 0x268, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL4__KEY_COL4    IOMUX_PAD(0x65C, 0x26C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL5__KEY_COL5    IOMUX_PAD(0x660, 0x270, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_USBH1_CLK__USBH1_CLK  IOMUX_PAD(0x678, 0x278, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DIR__USBH1_DIR  IOMUX_PAD(0x67C, 0x27C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_STP__USBH1_STP  IOMUX_PAD(0x680, 0x280, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_STP__GPIO_1_27  IOMUX_PAD(0x680, 0x280, IOMUX_CONFIG_GPIO, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_NXT__USBH1_NXT  IOMUX_PAD(0x684, 0x284, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA0__USBH1_DATA0      IOMUX_PAD(0x688, 0x288, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA1__USBH1_DATA1      IOMUX_PAD(0x68C, 0x28C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA2__USBH1_DATA2      IOMUX_PAD(0x690, 0x290, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA3__USBH1_DATA3      IOMUX_PAD(0x694, 0x294, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA4__USBH1_DATA4      IOMUX_PAD(0x698, 0x298, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA5__USBH1_DATA5      IOMUX_PAD(0x69C, 0x29C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA6__USBH1_DATA6      IOMUX_PAD(0x6A0, 0x2A0, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_USBH1_DATA7__USBH1_DATA7      IOMUX_PAD(0x6A4, 0x2A4, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
-#define MX51_PAD_GPIO_3_0__DI1_PIN11   IOMUX_PAD(0x6A8, 0x2A8, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_1__DI1_PIN12   IOMUX_PAD(0x6AC, 0x2AC, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_2__DI1_PIN13   IOMUX_PAD(0x6B0, 0x2B0, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_3__DI1_D0_CS   IOMUX_PAD(0x6B4, 0x2B4, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_4__DI1_D1_CS   IOMUX_PAD(0x6B8, 0x2B8, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_5__DISPB2_SER_DIN      IOMUX_PAD(0x6BC, 0x2BC, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_6__DISPB2_SER_DIO      IOMUX_PAD(0x6C0, 0x2C0, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_7__DISPB2_SER_CLK      IOMUX_PAD(0x6C4, 0x2C4, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_3_8__DISPB2_SER_RS       IOMUX_PAD(0x6C8, 0x2C8, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT0__DISP1_DAT0        IOMUX_PAD(0x6CC, 0x2CC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT1__DISP1_DAT1        IOMUX_PAD(0x6D0, 0x2D0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT2__DISP1_DAT2        IOMUX_PAD(0x6D4, 0x2D4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT3__DISP1_DAT3        IOMUX_PAD(0x6D8, 0x2D8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT4__DISP1_DAT4        IOMUX_PAD(0x6DC, 0x2DC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT5__DISP1_DAT5        IOMUX_PAD(0x6E0, 0x2E0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT6__DISP1_DAT6        IOMUX_PAD(0x6E4, 0x2E4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT7__DISP1_DAT7        IOMUX_PAD(0x6E8, 0x2E8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT8__DISP1_DAT8        IOMUX_PAD(0x6EC, 0x2EC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT9__DISP1_DAT9        IOMUX_PAD(0x6F0, 0x2F0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT10__DISP1_DAT10      IOMUX_PAD(0x6F4, 0x2F4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT11__DISP1_DAT11      IOMUX_PAD(0x6F8, 0x2F8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT12__DISP1_DAT12      IOMUX_PAD(0x6FC, 0x2FC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT13__DISP1_DAT13      IOMUX_PAD(0x700, 0x300, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT14__DISP1_DAT14      IOMUX_PAD(0x704, 0x304, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT15__DISP1_DAT15      IOMUX_PAD(0x708, 0x308, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT16__DISP1_DAT16      IOMUX_PAD(0x70C, 0x30C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT17__DISP1_DAT17      IOMUX_PAD(0x710, 0x310, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT18__DISP1_DAT18      IOMUX_PAD(0x714, 0x314, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT19__DISP1_DAT19      IOMUX_PAD(0x718, 0x318, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT20__DISP1_DAT20      IOMUX_PAD(0x71C, 0x31C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT21__DISP1_DAT21      IOMUX_PAD(0x720, 0x320, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT22__DISP1_DAT22      IOMUX_PAD(0x724, 0x324, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP1_DAT23__DISP1_DAT23      IOMUX_PAD(0x728, 0x328, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_PIN3__DI1_PIN3    IOMUX_PAD(0x72C, 0x32C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_PIN2__DI1_PIN2    IOMUX_PAD(0x734, 0x330, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI_GP1__DI_GP1        IOMUX_PAD(0x73C, 0x334, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI_GP2__DI_GP2        IOMUX_PAD(0x740, 0x338, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI_GP3__DI_GP3        IOMUX_PAD(0x744, 0x33C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI2_PIN4__DI2_PIN4    IOMUX_PAD(0x748, 0x340, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI2_PIN2__DI2_PIN2    IOMUX_PAD(0x74C, 0x344, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI2_PIN3__DI2_PIN3    IOMUX_PAD(0x750, 0x348, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK    IOMUX_PAD(0x754, 0x34C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DI_GP4__DI_GP4        IOMUX_PAD(0x758, 0x350, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT0__DISP2_DAT0        IOMUX_PAD(0x75C, 0x354, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT1__DISP2_DAT1        IOMUX_PAD(0x760, 0x358, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT2__DISP2_DAT2        IOMUX_PAD(0x764, 0x35C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT3__DISP2_DAT3        IOMUX_PAD(0x768, 0x360, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT4__DISP2_DAT4        IOMUX_PAD(0x76C, 0x364, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT5__DISP2_DAT5        IOMUX_PAD(0x770, 0x368, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_19__DISP2_DAT6 IOMUX_PAD(0x774, 0x36C, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_29__DISP2_DAT7 IOMUX_PAD(0x778, 0x370, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_30__DISP2_DAT8 IOMUX_PAD(0x77C, 0x374, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_31__DISP2_DAT9 IOMUX_PAD(0x780, 0x378, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT10__DISP2_DAT10      IOMUX_PAD(0x784, 0x37C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT11__DISP2_DAT11      IOMUX_PAD(0x788, 0x380, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT12__DISP2_DAT12      IOMUX_PAD(0x78C, 0x384, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT13__DISP2_DAT13      IOMUX_PAD(0x790, 0x388, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT14__DISP2_DAT14      IOMUX_PAD(0x794, 0x38C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT15__DISP2_DAT15      IOMUX_PAD(0x798, 0x390, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_CMD__SD1_CMD      IOMUX_PAD(0x79C, 0x394, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_CLK__SD1_CLK      IOMUX_PAD(0x7A0, 0x398, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA0__SD1_DATA0  IOMUX_PAD(0x7A4, 0x39C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA1__SD1_DATA1  IOMUX_PAD(0x7A8, 0x3A0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA2__SD1_DATA2  IOMUX_PAD(0x7AC, 0x3A4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA3__SD1_DATA3  IOMUX_PAD(0x7B0, 0x3A8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_0__GPIO1_0     IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_1__GPIO1_1     IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CMD__SD2_CMD      IOMUX_PAD(0x7BC, 0x3B4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CLK__SD2_CLK      IOMUX_PAD(0x7C0, 0x3B8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA0__SD2_DATA0  IOMUX_PAD(0x7C4, 0x3BC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA1__SD2_DATA1  IOMUX_PAD(0x7C8, 0x3C0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA2__SD2_DATA2  IOMUX_PAD(0x7CC, 0x3C4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA3__SD2_DATA3  IOMUX_PAD(0x7D0, 0x3C8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_2__GPIO1_2     IOMUX_PAD(0x7D4, 0x3CC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_3__GPIO1_3     IOMUX_PAD(0x7D8, 0x3D0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ    IOMUX_PAD(0x7FC, 0x3D4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_4__GPIO1_4     IOMUX_PAD(0x804, 0x3D8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_5__GPIO1_5     IOMUX_PAD(0x808, 0x3DC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_6__GPIO1_6     IOMUX_PAD(0x80C, 0x3E0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_7__GPIO1_7     IOMUX_PAD(0x810, 0x3E4, 0, 0x0, 0, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_8__GPIO1_8     IOMUX_PAD(0x814, 0x3E8, 0, 0x0, 1, \
-                                               (PAD_CTL_SRE_SLOW | PAD_CTL_DSE_MED | PAD_CTL_PUS_100K_UP |  PAD_CTL_HYS))
-#define MX51_PAD_GPIO_1_9__GPIO1_9     IOMUX_PAD(0x818, 0x3EC, 0, 0x0, 0, NO_PAD_CTRL)
-
-/* EIM */
-#define MX51_PAD_EIM_DA0__EIM_DA0      IOMUX_PAD(0x7a8, 0x01c, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA1__EIM_DA1      IOMUX_PAD(0x7a8, 0x020, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA2__EIM_DA2      IOMUX_PAD(0x7a8, 0x024, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA3__EIM_DA3      IOMUX_PAD(0x7a8, 0x028, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA4__EIM_DA4      IOMUX_PAD(0x7ac, 0x02c, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA5__EIM_DA5      IOMUX_PAD(0x7ac, 0x030, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA6__EIM_DA6      IOMUX_PAD(0x7ac, 0x034, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA7__EIM_DA7      IOMUX_PAD(0x7ac, 0x038, 0, 0x0,   0, NO_PAD_CTRL)
-
-#define MX51_PAD_EIM_DA8__EIM_DA8      IOMUX_PAD(0x7b0, 0x03c, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA9__EIM_DA9      IOMUX_PAD(0x7b0, 0x040, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA10__EIM_DA10    IOMUX_PAD(0x7b0, 0x044, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA11__EIM_DA11    IOMUX_PAD(0x7b0, 0x048, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA12__EIM_DA12    IOMUX_PAD(0x7bc, 0x04c, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA13__EIM_DA13    IOMUX_PAD(0x7bc, 0x050, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA14__EIM_DA14    IOMUX_PAD(0x7bc, 0x054, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_EIM_DA15__EIM_DA15    IOMUX_PAD(0x7bc, 0x058, 0, 0x0,   0, NO_PAD_CTRL)
+/*                                                       PAD    MUX   ALT INPSE PATH PADCTRL */
+#define MX51_PAD_EIM_DA0__EIM_DA0              IOMUX_PAD(0x7a8, 0x01c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA1__EIM_DA1              IOMUX_PAD(0x7a8, 0x020, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA2__EIM_DA2              IOMUX_PAD(0x7a8, 0x024, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA3__EIM_DA3              IOMUX_PAD(0x7a8, 0x028, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA4__EIM_DA4              IOMUX_PAD(0x7ac, 0x02c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA5__EIM_DA5              IOMUX_PAD(0x7ac, 0x030, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA6__EIM_DA6              IOMUX_PAD(0x7ac, 0x034, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA7__EIM_DA7              IOMUX_PAD(0x7ac, 0x038, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA8__EIM_DA8              IOMUX_PAD(0x7b0, 0x03c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA9__EIM_DA9              IOMUX_PAD(0x7b0, 0x040, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA10__EIM_DA10            IOMUX_PAD(0x7b0, 0x044, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA11__EIM_DA11            IOMUX_PAD(0x7b0, 0x048, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA12__EIM_DA12            IOMUX_PAD(0x7bc, 0x04c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA13__EIM_DA13            IOMUX_PAD(0x7bc, 0x050, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA14__EIM_DA14            IOMUX_PAD(0x7bc, 0x054, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DA15__EIM_DA15            IOMUX_PAD(0x7bc, 0x058, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D16__GPIO_2_0              IOMUX_PAD(0x3f0, 0x05c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D16__I2C1_SDA             IOMUX_PAD(0x3f0, 0x05c, (4 | IOMUX_CONFIG_SION), \
+                                                       0x09b4, 0, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_EIM_D17__GPIO_2_1              IOMUX_PAD(0x3f4, 0x060, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D18__GPIO_2_2              IOMUX_PAD(0x3f8, 0x064, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D19__GPIO_2_3              IOMUX_PAD(0x3fc, 0x068, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D19__I2C1_SCL             IOMUX_PAD(0x3fc, 0x068, (4 | IOMUX_CONFIG_SION), \
+                                                       0x09b0, 0, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_EIM_D20__GPIO_2_4              IOMUX_PAD(0x400, 0x06c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D21__GPIO_2_5             IOMUX_PAD(0x404, 0x070, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_EIM_D22__GPIO_2_6              IOMUX_PAD(0x408, 0x074, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D23__GPIO_2_7              IOMUX_PAD(0x40c, 0x078, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D24__UART3_CTS             IOMUX_PAD(0x410, 0x07c, 3, 0x0,   0, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_EIM_D25__UART3_RXD             IOMUX_PAD(0x414, 0x080, 3, 0x9f4, 0, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_EIM_D25__UART2_CTS            IOMUX_PAD(0x414, 0x080, 4, 0x0,   0, MX51_UART2_PAD_CTRL)
+#define MX51_PAD_EIM_D26__UART3_TXD             IOMUX_PAD(0x418, 0x084, 3, 0x0,   0, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_EIM_D26__UART2_RTS            IOMUX_PAD(0x418, 0x084, 4, 0x9e8, 3, MX51_UART2_PAD_CTRL)
+#define MX51_PAD_EIM_D27__UART3_RTS             IOMUX_PAD(0x41c, 0x088, 3, 0x9f0, 3, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_EIM_D28__EIM_D28               IOMUX_PAD(0x420, 0x08c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D29__EIM_D29               IOMUX_PAD(0x424, 0x090, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D30__EIM_D30               IOMUX_PAD(0x428, 0x094, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D31__EIM_D31               IOMUX_PAD(0x42c, 0x09c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A16__GPIO_2_10             IOMUX_PAD(0x430, 0x09c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A17__GPIO_2_11             IOMUX_PAD(0x434, 0x0a0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A18__GPIO_2_12             IOMUX_PAD(0x438, 0x0a4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A19__GPIO_2_13             IOMUX_PAD(0x43c, 0x0a8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A20__GPIO_2_14             IOMUX_PAD(0x440, 0x0ac, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A21__GPIO_2_15             IOMUX_PAD(0x444, 0x0b0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A22__GPIO_2_16             IOMUX_PAD(0x448, 0x0b4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A23__GPIO_2_17             IOMUX_PAD(0x44c, 0x0b8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A24__GPIO_2_18             IOMUX_PAD(0x450, 0x0bc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A25__GPIO_2_19             IOMUX_PAD(0x454, 0x0c0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A26__GPIO_2_20             IOMUX_PAD(0x458, 0x0c4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_A27__GPIO_2_21             IOMUX_PAD(0x45c, 0x0c8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB0__EIM_EB0               IOMUX_PAD(0x460, 0x0cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB1__EIM_EB1               IOMUX_PAD(0x464, 0x0d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB2__GPIO_2_22             IOMUX_PAD(0x468, 0x0d4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB3__GPIO_2_23             IOMUX_PAD(0x46c, 0x0d8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_OE__GPIO_2_24              IOMUX_PAD(0x470, 0x0dc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS0__GPIO_2_25             IOMUX_PAD(0x474, 0x0e0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS1__GPIO_2_26             IOMUX_PAD(0x478, 0x0e4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS2__GPIO_2_27             IOMUX_PAD(0x47c, 0x0e8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS3__GPIO_2_28             IOMUX_PAD(0x480, 0x0ec, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS4__GPIO_2_29             IOMUX_PAD(0x484, 0x0f0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS5__GPIO_2_30             IOMUX_PAD(0x488, 0x0f4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_DTACK__GPIO_2_31           IOMUX_PAD(0x48c, 0x0f8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_LBA__GPIO_3_1              IOMUX_PAD(0x494, 0x0FC, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CRE__GPIO_3_2              IOMUX_PAD(0x4A0, 0x100, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DRAM_CS1__DRAM_CS1             IOMUX_PAD(0x4D0, 0x104, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_WE_B__GPIO_3_3           IOMUX_PAD(0x4E4, 0x108, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RE_B__GPIO_3_4           IOMUX_PAD(0x4E8, 0x10C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_ALE__GPIO_3_5            IOMUX_PAD(0x4EC, 0x110, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CLE__GPIO_3_6            IOMUX_PAD(0x4F0, 0x114, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_WP_B__GPIO_3_7           IOMUX_PAD(0x4F4, 0x118, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB0__GPIO_3_8            IOMUX_PAD(0x4F8, 0x11C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB1__GPIO_3_9            IOMUX_PAD(0x4FC, 0x120, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__GPIO_3_10           IOMUX_PAD(0x500, 0x124, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__GPIO_3_11           IOMUX_PAD(0x504, 0x128, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_NAND__GPIO_3_12           IOMUX_PAD(0x514, 0x12C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS0__GPIO_3_16           IOMUX_PAD(0x518, 0x130, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS1__GPIO_3_17           IOMUX_PAD(0x51C, 0x134, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS2__GPIO_3_18           IOMUX_PAD(0x520, 0x138, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS3__GPIO_3_19           IOMUX_PAD(0x524, 0x13C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS4__GPIO_3_20           IOMUX_PAD(0x528, 0x140, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS5__GPIO_3_21           IOMUX_PAD(0x52C, 0x144, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS6__GPIO_3_22           IOMUX_PAD(0x530, 0x148, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS7__GPIO_3_23           IOMUX_PAD(0x534, 0x14C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RDY_INT__GPIO_3_24       IOMUX_PAD(0x538, 0x150, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D15__GPIO_3_25           IOMUX_PAD(0x53C, 0x154, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D14__GPIO_3_26           IOMUX_PAD(0x540, 0x158, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D13__GPIO_3_27           IOMUX_PAD(0x544, 0x15C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D12__GPIO_3_28           IOMUX_PAD(0x548, 0x160, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D11__GPIO_3_29           IOMUX_PAD(0x54C, 0x164, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D10__GPIO_3_30           IOMUX_PAD(0x550, 0x168, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D9__GPIO_3_31            IOMUX_PAD(0x554, 0x16C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D8__GPIO_4_0             IOMUX_PAD(0x558, 0x170, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D7__GPIO_4_1             IOMUX_PAD(0x55C, 0x174, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D6__GPIO_4_2             IOMUX_PAD(0x560, 0x178, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D5__GPIO_4_3             IOMUX_PAD(0x564, 0x17C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D4__GPIO_4_4             IOMUX_PAD(0x568, 0x180, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D3__GPIO_4_5             IOMUX_PAD(0x56C, 0x184, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D2__GPIO_4_6             IOMUX_PAD(0x570, 0x188, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D1__GPIO_4_7             IOMUX_PAD(0x574, 0x18C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D0__GPIO_4_8             IOMUX_PAD(0x578, 0x190, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D8__GPIO_3_12             IOMUX_PAD(0x57C, 0x194, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D9__GPIO_3_13             IOMUX_PAD(0x580, 0x198, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D10__CSI1_D10             IOMUX_PAD(0x584, 0x19C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D11__CSI1_D11             IOMUX_PAD(0x588, 0x1A0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D12__CSI1_D12             IOMUX_PAD(0x58C, 0x1A4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D13__CSI1_D13             IOMUX_PAD(0x590, 0x1A8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D14__CSI1_D14             IOMUX_PAD(0x594, 0x1AC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D15__CSI1_D15             IOMUX_PAD(0x598, 0x1B0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D16__CSI1_D16             IOMUX_PAD(0x59C, 0x1B4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D17__CSI1_D17             IOMUX_PAD(0x5A0, 0x1B8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D18__CSI1_D18             IOMUX_PAD(0x5A4, 0x1BC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_D19__CSI1_D19             IOMUX_PAD(0x5A8, 0x1C0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_VSYNC__CSI1_VSYNC         IOMUX_PAD(0x5AC, 0x1C4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_HSYNC__CSI1_HSYNC         IOMUX_PAD(0x5B0, 0x1C8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_PIXCLK__CSI1_PIXCLK       IOMUX_PAD(0x5B4, 0x000, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_MCLK__CSI1_MCLK           IOMUX_PAD(0x5B8, 0x000, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI1_PKE0__CSI1_PKE0           IOMUX_PAD(0x860, 0x000, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D12__GPIO_4_9             IOMUX_PAD(0x5BC, 0x1CC, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D13__GPIO_4_10            IOMUX_PAD(0x5C0, 0x1D0, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D14__GPIO_4_11            IOMUX_PAD(0x5C4, 0x1D4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D15__GPIO_4_12            IOMUX_PAD(0x5C8, 0x1D8, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D16__GPIO_4_11            IOMUX_PAD(0x5CC, 0x1DC, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D17__GPIO_4_12            IOMUX_PAD(0x5D0, 0x1E0, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D18__GPIO_4_11            IOMUX_PAD(0x5D4, 0x1E4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_D19__GPIO_4_12            IOMUX_PAD(0x5D8, 0x1E8, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_VSYNC__GPIO_4_13          IOMUX_PAD(0x5DC, 0x1EC, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_HSYNC__GPIO_4_14          IOMUX_PAD(0x5E0, 0x1F0, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSI2_PIXCLK__GPIO_4_15         IOMUX_PAD(0x5E4, 0x1F4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_I2C1_CLK__GPIO_4_16            IOMUX_PAD(0x5E8, 0x1F8, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_I2C1_CLK__HSI2C_CLK           IOMUX_PAD(0x5E8, 0x1F8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_I2C1_DAT__GPIO_4_17            IOMUX_PAD(0x5EC, 0x1FC, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_I2C1_DAT__HSI2C_DAT           IOMUX_PAD(0x5EC, 0x1FC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_TXD__GPIO_4_18         IOMUX_PAD(0x5F0, 0x200, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_RXD__GPIO_4_19         IOMUX_PAD(0x5F4, 0x204, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_CK__GPIO_4_20          IOMUX_PAD(0x5F8, 0x208, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_FS__GPIO_4_21          IOMUX_PAD(0x5FC, 0x20C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_MOSI__GPIO_4_22          IOMUX_PAD(0x600, 0x210, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_MISO__GPIO_4_23          IOMUX_PAD(0x604, 0x214, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SS0__GPIO_4_24           IOMUX_PAD(0x608, 0x218, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SS1__GPIO_4_25           IOMUX_PAD(0x60C, 0x21C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_RDY__GPIO_4_26           IOMUX_PAD(0x610, 0x220, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SCLK__GPIO_4_27          IOMUX_PAD(0x614, 0x224, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_UART1_RXD__UART1_RXD           IOMUX_PAD(0x618, 0x228, 0, 0x9e4, 0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
+#define MX51_PAD_UART1_TXD__UART1_TXD           IOMUX_PAD(0x61C, 0x22C, 0, 0x0,   0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
+#define MX51_PAD_UART1_RTS__UART1_RTS           IOMUX_PAD(0x620, 0x230, 0, 0x9e0, 0, MX51_UART1_PAD_CTRL)
+#define MX51_PAD_UART1_CTS__UART1_CTS           IOMUX_PAD(0x624, 0x234, 0, 0x0,   0, MX51_UART1_PAD_CTRL)
+#define MX51_PAD_UART2_RXD__UART2_RXD           IOMUX_PAD(0x628, 0x238, 0, 0x9ec, 2, MX51_UART2_PAD_CTRL)
+#define MX51_PAD_UART2_TXD__UART2_TXD           IOMUX_PAD(0x62C, 0x23C, 0, 0x0,   0, MX51_UART2_PAD_CTRL)
+#define MX51_PAD_UART3_RXD__UART3_RXD          IOMUX_PAD(0x630, 0x240, 1, 0x9f4, 4, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_UART3_RXD__GPIO_1_22           IOMUX_PAD(0x630, 0x240, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_UART3_TXD__UART3_TXD          IOMUX_PAD(0x634, 0x244, 1, 0x0,   0, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_UART3_TXD__GPIO_1_23           IOMUX_PAD(0x634, 0x244, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_OWIRE_LINE__GPIO_1_24          IOMUX_PAD(0x638, 0x248, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_ROW0__KEY_ROW0             IOMUX_PAD(0x63C, 0x24C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_ROW1__KEY_ROW1             IOMUX_PAD(0x640, 0x250, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_ROW2__KEY_ROW2             IOMUX_PAD(0x644, 0x254, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_ROW3__KEY_ROW3             IOMUX_PAD(0x648, 0x258, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL0__KEY_COL0             IOMUX_PAD(0x64C, 0x25C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL1__KEY_COL1             IOMUX_PAD(0x650, 0x260, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL2__KEY_COL2             IOMUX_PAD(0x654, 0x264, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL3__KEY_COL3             IOMUX_PAD(0x658, 0x268, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL4__KEY_COL4             IOMUX_PAD(0x65C, 0x26C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL4__UART3_RTS           IOMUX_PAD(0x65C, 0x26C, 2, 0x9f0, 4, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_KEY_COL4__I2C2_SCL            IOMUX_PAD(0x65C, 0x26C, (3 | IOMUX_CONFIG_SION), \
+                                                       0x09b8, 1, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_KEY_COL5__KEY_COL5             IOMUX_PAD(0x660, 0x270, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL5__UART3_CTS           IOMUX_PAD(0x660, 0x270, 2, 0,     0, MX51_UART3_PAD_CTRL)
+#define MX51_PAD_KEY_COL5__I2C2_SDA            IOMUX_PAD(0x660, 0x270, (3 | IOMUX_CONFIG_SION), \
+                                                       0x09bc, 1, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_USBH1_CLK__USBH1_CLK           IOMUX_PAD(0x678, 0x278, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DIR__USBH1_DIR           IOMUX_PAD(0x67C, 0x27C, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_STP__USBH1_STP           IOMUX_PAD(0x680, 0x280, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_STP__GPIO_1_27           IOMUX_PAD(0x680, 0x280, 2, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_NXT__USBH1_NXT           IOMUX_PAD(0x684, 0x284, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA0__USBH1_DATA0       IOMUX_PAD(0x688, 0x288, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA1__USBH1_DATA1       IOMUX_PAD(0x68C, 0x28C, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA2__USBH1_DATA2       IOMUX_PAD(0x690, 0x290, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA3__USBH1_DATA3       IOMUX_PAD(0x694, 0x294, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA4__USBH1_DATA4       IOMUX_PAD(0x698, 0x298, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA5__USBH1_DATA5       IOMUX_PAD(0x69C, 0x29C, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA6__USBH1_DATA6       IOMUX_PAD(0x6A0, 0x2A0, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_USBH1_DATA7__USBH1_DATA7       IOMUX_PAD(0x6A4, 0x2A4, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
+#define MX51_PAD_DI1_PIN11__GPIO_3_0            IOMUX_PAD(0x6A8, 0x2A8, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN12__GPIO_3_1            IOMUX_PAD(0x6AC, 0x2AC, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN13__GPIO_3_2            IOMUX_PAD(0x6B0, 0x2B0, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_D0_CS__GPIO_3_3            IOMUX_PAD(0x6B4, 0x2B4, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_D1_CS__GPIO_3_4            IOMUX_PAD(0x6B8, 0x2B8, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_DIN__GPIO_3_5       IOMUX_PAD(0x6BC, 0x2BC, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_DIO__GPIO_3_6       IOMUX_PAD(0x6C0, 0x2C0, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_CLK__GPIO_3_7       IOMUX_PAD(0x6C4, 0x2C4, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_RS__GPIO_3_8        IOMUX_PAD(0x6C8, 0x2C8, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT0__DISP1_DAT0         IOMUX_PAD(0x6CC, 0x2CC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT1__DISP1_DAT1         IOMUX_PAD(0x6D0, 0x2D0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT2__DISP1_DAT2         IOMUX_PAD(0x6D4, 0x2D4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT3__DISP1_DAT3         IOMUX_PAD(0x6D8, 0x2D8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT4__DISP1_DAT4         IOMUX_PAD(0x6DC, 0x2DC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT5__DISP1_DAT5         IOMUX_PAD(0x6E0, 0x2E0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT6__DISP1_DAT6         IOMUX_PAD(0x6E4, 0x2E4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT7__DISP1_DAT7         IOMUX_PAD(0x6E8, 0x2E8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT8__DISP1_DAT8         IOMUX_PAD(0x6EC, 0x2EC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT9__DISP1_DAT9         IOMUX_PAD(0x6F0, 0x2F0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT10__DISP1_DAT10       IOMUX_PAD(0x6F4, 0x2F4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT11__DISP1_DAT11       IOMUX_PAD(0x6F8, 0x2F8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT12__DISP1_DAT12       IOMUX_PAD(0x6FC, 0x2FC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT13__DISP1_DAT13       IOMUX_PAD(0x700, 0x300, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT14__DISP1_DAT14       IOMUX_PAD(0x704, 0x304, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT15__DISP1_DAT15       IOMUX_PAD(0x708, 0x308, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT16__DISP1_DAT16       IOMUX_PAD(0x70C, 0x30C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT17__DISP1_DAT17       IOMUX_PAD(0x710, 0x310, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT18__DISP1_DAT18       IOMUX_PAD(0x714, 0x314, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT19__DISP1_DAT19       IOMUX_PAD(0x718, 0x318, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT20__DISP1_DAT20       IOMUX_PAD(0x71C, 0x31C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT21__DISP1_DAT21       IOMUX_PAD(0x720, 0x320, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT22__DISP1_DAT22       IOMUX_PAD(0x724, 0x324, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP1_DAT23__DISP1_DAT23       IOMUX_PAD(0x728, 0x328, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN3__DI1_PIN3             IOMUX_PAD(0x72C, 0x32C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN2__DI1_PIN2             IOMUX_PAD(0x734, 0x330, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI_GP1__DI_GP1                 IOMUX_PAD(0x73C, 0x334, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI_GP2__DI_GP2                 IOMUX_PAD(0x740, 0x338, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI_GP3__DI_GP3                 IOMUX_PAD(0x744, 0x33C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI2_PIN4__DI2_PIN4             IOMUX_PAD(0x748, 0x340, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI2_PIN2__DI2_PIN2             IOMUX_PAD(0x74C, 0x344, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI2_PIN3__DI2_PIN3             IOMUX_PAD(0x750, 0x348, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK     IOMUX_PAD(0x754, 0x34C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI_GP4__DI_GP4                 IOMUX_PAD(0x758, 0x350, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT0__DISP2_DAT0         IOMUX_PAD(0x75C, 0x354, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT1__DISP2_DAT1         IOMUX_PAD(0x760, 0x358, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT2__DISP2_DAT2         IOMUX_PAD(0x764, 0x35C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT3__DISP2_DAT3         IOMUX_PAD(0x768, 0x360, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT4__DISP2_DAT4         IOMUX_PAD(0x76C, 0x364, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT5__DISP2_DAT5         IOMUX_PAD(0x770, 0x368, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT6__GPIO_1_19          IOMUX_PAD(0x774, 0x36C, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT7__GPIO_1_29          IOMUX_PAD(0x778, 0x370, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT8__GPIO_1_30          IOMUX_PAD(0x77C, 0x374, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT9__GPIO_1_31          IOMUX_PAD(0x780, 0x378, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT10__DISP2_DAT10       IOMUX_PAD(0x784, 0x37C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT11__DISP2_DAT11       IOMUX_PAD(0x788, 0x380, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT12__DISP2_DAT12       IOMUX_PAD(0x78C, 0x384, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT13__DISP2_DAT13       IOMUX_PAD(0x790, 0x388, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT14__DISP2_DAT14       IOMUX_PAD(0x794, 0x38C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT15__DISP2_DAT15       IOMUX_PAD(0x798, 0x390, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_CMD__SD1_CMD               IOMUX_PAD(0x79C, 0x394, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_CLK__SD1_CLK               IOMUX_PAD(0x7A0, 0x398, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA0__SD1_DATA0           IOMUX_PAD(0x7A4, 0x39C, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA1__SD1_DATA1           IOMUX_PAD(0x7A8, 0x3A0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA2__SD1_DATA2           IOMUX_PAD(0x7AC, 0x3A4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA3__SD1_DATA3           IOMUX_PAD(0x7B0, 0x3A8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_0__GPIO_1_0            IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_1__GPIO_1_1            IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_CMD__SD2_CMD               IOMUX_PAD(0x7BC, 0x3B4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_CLK__SD2_CLK               IOMUX_PAD(0x7C0, 0x3B8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA0__SD2_DATA0           IOMUX_PAD(0x7C4, 0x3BC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA1__SD2_DATA1           IOMUX_PAD(0x7C8, 0x3C0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA2__SD2_DATA2           IOMUX_PAD(0x7CC, 0x3C4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA3__SD2_DATA3           IOMUX_PAD(0x7D0, 0x3C8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_2__GPIO_1_2            IOMUX_PAD(0x7D4, 0x3CC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_2__I2C2_SCL            IOMUX_PAD(0x7D4, 0x3CC, (2 | IOMUX_CONFIG_SION), \
+                                                       0x9b8,   3, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_GPIO_1_3__GPIO_1_3            IOMUX_PAD(0x7D8, 0x3D0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_3__I2C2_SDA            IOMUX_PAD(0x7D8, 0x3D0, (2 | IOMUX_CONFIG_SION), \
+                                                       0x9bc,   3, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ    IOMUX_PAD(0x7FC, 0x3D4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_4__GPIO_1_4            IOMUX_PAD(0x804, 0x3D8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_5__GPIO_1_5            IOMUX_PAD(0x808, 0x3DC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_6__GPIO_1_6            IOMUX_PAD(0x80C, 0x3E0, 0, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_7__GPIO_1_7            IOMUX_PAD(0x810, 0x3E4, 0, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_8__GPIO_1_8            IOMUX_PAD(0x814, 0x3E8, 0, 0x0,   1, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_9__GPIO_1_9            IOMUX_PAD(0x818, 0x3EC, 0, 0x0,   0, NO_PAD_CTRL)
 
 #endif /* __MACH_IOMUX_MX51_H__ */
index 3887f3fe29d4401b62584a905fcaa642dd7a80b6..15d59510f597ed8eb5e37df2c44a5c34cdc6dcc9 100644 (file)
  * 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 __MACH_IOMUX_MXC91231_H__
index f2f73d31d5ba5cf579d035b52b9f106c4f741d0d..0880a4a1aed1e91c397653515dca3d979cf9b804 100644 (file)
@@ -89,6 +89,21 @@ struct pad_desc {
 #define PAD_CTL_SRE_FAST               (1 << 0)
 #define PAD_CTL_SRE_SLOW               (0 << 0)
 
+
+#define MX51_NUM_GPIO_PORT     4
+
+#define GPIO_PIN_MASK 0x1f
+
+#define GPIO_PORT_SHIFT 5
+#define GPIO_PORT_MASK (0x7 << GPIO_PORT_SHIFT)
+
+#define GPIO_PORTA     (0 << GPIO_PORT_SHIFT)
+#define GPIO_PORTB     (1 << GPIO_PORT_SHIFT)
+#define GPIO_PORTC     (2 << GPIO_PORT_SHIFT)
+#define GPIO_PORTD     (3 << GPIO_PORT_SHIFT)
+#define GPIO_PORTE     (4 << GPIO_PORT_SHIFT)
+#define GPIO_PORTF     (5 << GPIO_PORT_SHIFT)
+
 /*
  * setups a single pad in the iomuxer
  */
index c4b40c35a6a1e429f14476a4f76491229c8560cc..564ec9dbc93d324a208cf407de178974435e9eea 100644 (file)
  */
 #define CONSISTENT_DMA_SIZE SZ_8M
 
-#elif defined(CONFIG_MX1_VIDEO)
+#elif defined(CONFIG_MX1_VIDEO) || defined(CONFIG_VIDEO_MX2_HOSTSUPPORT)
 /*
  * Increase size of DMA-consistent memory region.
  * This is required for i.MX camera driver to capture at least four VGA frames.
  */
 #define CONSISTENT_DMA_SIZE SZ_4M
-#endif /* CONFIG_MX1_VIDEO */
+#endif /* CONFIG_MX1_VIDEO || CONFIG_VIDEO_MX2_HOSTSUPPORT */
 
 #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
index de2128dada5cf2856118181bec1771fddef95fac..29115f405af91653683465fa9112fd0cff78213f 100644 (file)
@@ -31,6 +31,9 @@ struct imxmmc_platform_data {
 
        /* adjust slot voltage */
        void (*setpower)(struct device *, unsigned int vdd);
+
+       /* enable card detect using DAT3 */
+       int dat3_card_detect;
 };
 
 #endif
index 5eba7e6785dec6ddf643366965c5734bdc1fa89a..641b2461823950be06d2573131f7f2b8ba74d3e4 100644 (file)
 #define MX1_SIM_DATA_INT       16
 #define MX1_RTC_INT            17
 #define MX1_RTC_SAMINT         18
-#define MX1_UART2_MINT_PFERR   19
-#define MX1_UART2_MINT_RTS     20
-#define MX1_UART2_MINT_DTR     21
-#define MX1_UART2_MINT_UARTC   22
-#define MX1_UART2_MINT_TX      23
-#define MX1_UART2_MINT_RX      24
-#define MX1_UART1_MINT_PFERR   25
-#define MX1_UART1_MINT_RTS     26
-#define MX1_UART1_MINT_DTR     27
-#define MX1_UART1_MINT_UARTC   28
-#define MX1_UART1_MINT_TX      29
-#define MX1_UART1_MINT_RX      30
+#define MX1_INT_UART2PFERR     19
+#define MX1_INT_UART2RTS       20
+#define MX1_INT_UART2DTR       21
+#define MX1_INT_UART2UARTC     22
+#define MX1_INT_UART2TX                23
+#define MX1_INT_UART2RX                24
+#define MX1_INT_UART1PFERR     25
+#define MX1_INT_UART1RTS       26
+#define MX1_INT_UART1DTR       27
+#define MX1_INT_UART1UARTC     28
+#define MX1_INT_UART1TX                29
+#define MX1_INT_UART1RX                30
 #define MX1_VOICE_DAC_INT      31
 #define MX1_VOICE_ADC_INT      32
 #define MX1_PEN_DATA_INT       33
 #define MX1_PWM_INT            34
 #define MX1_SDHC_INT           35
-#define MX1_I2C_INT            39
+#define MX1_INT_I2C            39
 #define MX1_CSPI_INT           41
 #define MX1_SSI_TX_INT         42
 #define MX1_SSI_TX_ERR_INT     43
 #define PEN_DATA_INT MX1_PEN_DATA_INT
 #define PWM_INT MX1_PWM_INT
 #define SDHC_INT MX1_SDHC_INT
-#define I2C_INT MX1_I2C_INT
+#define I2C_INT MX1_INT_I2C
 #define CSPI_INT MX1_CSPI_INT
 #define SSI_TX_INT MX1_SSI_TX_INT
 #define SSI_TX_ERR_INT MX1_SSI_TX_ERR_INT
index 4eb6e334bda589f6d210dc2c3de1a70a60cb6b1b..4a6f800990f83a826e687ae6a8d8776def7a3689 100644 (file)
 #define MX25_AVIC_BASE_ADDR_VIRT       0xfc400000
 #define MX25_AVIC_SIZE                 SZ_1M
 
+#define MX25_I2C1_BASE_ADDR            (MX25_AIPS1_BASE_ADDR + 0x80000)
+#define MX25_I2C3_BASE_ADDR            (MX25_AIPS1_BASE_ADDR + 0x84000)
+#define MX25_CAN1_BASE_ADDR            (MX25_AIPS1_BASE_ADDR + 0x88000)
+#define MX25_CAN2_BASE_ADDR            (MX25_AIPS1_BASE_ADDR + 0x8c000)
+#define MX25_I2C2_BASE_ADDR            (MX25_AIPS1_BASE_ADDR + 0x98000)
+#define MX25_CSPI1_BASE_ADDR           (MX25_AIPS1_BASE_ADDR + 0xa4000)
 #define MX25_IOMUXC_BASE_ADDR          (MX25_AIPS1_BASE_ADDR + 0xac000)
 
 #define MX25_CRM_BASE_ADDR             (MX25_AIPS2_BASE_ADDR + 0x80000)
        IMX_IO_ADDRESS(x, MX25_AIPS2) ?:                        \
        IMX_IO_ADDRESS(x, MX25_AVIC))
 
+#define MX25_AIPS1_IO_ADDRESS(x) \
+       (((x) - MX25_AIPS1_BASE_ADDR) + MX25_AIPS1_BASE_ADDR_VIRT)
+
 #define MX25_UART1_BASE_ADDR           0x43f90000
 #define MX25_UART2_BASE_ADDR           0x43f94000
+#define MX25_AUDMUX_BASE_ADDR          0x43fb0000
+#define MX25_UART3_BASE_ADDR           0x5000c000
+#define MX25_UART4_BASE_ADDR           0x50008000
+#define MX25_UART5_BASE_ADDR           0x5002c000
 
+#define MX25_CSPI3_BASE_ADDR           0x50004000
+#define MX25_CSPI2_BASE_ADDR           0x50010000
 #define MX25_FEC_BASE_ADDR             0x50038000
+#define MX25_SSI2_BASE_ADDR            0x50014000
+#define MX25_SSI1_BASE_ADDR            0x50034000
 #define MX25_NFC_BASE_ADDR             0xbb000000
 #define MX25_DRYICE_BASE_ADDR          0x53ffc000
 #define MX25_LCDC_BASE_ADDR            0x53fbc000
+#define MX25_KPP_BASE_ADDR             0x43fa8000
+#define MX25_OTG_BASE_ADDR             0x53ff4000
+#define MX25_CSI_BASE_ADDR             0x53ff8000
 
-#define MX25_INT_DRYICE        25
-#define MX25_INT_FEC   57
-#define MX25_INT_NANDFC        33
-#define MX25_INT_LCDC  39
-
-#if defined(IMX_NEEDS_DEPRECATED_SYMBOLS)
-#define UART1_BASE_ADDR                        MX25_UART1_BASE_ADDR
-#define UART2_BASE_ADDR                        MX25_UART2_BASE_ADDR
-#endif
+#define MX25_INT_CSPI3         0
+#define MX25_INT_I2C1          3
+#define MX25_INT_I2C2          4
+#define MX25_INT_UART4         5
+#define MX25_INT_I2C3          10
+#define MX25_INT_SSI2          11
+#define MX25_INT_SSI1          12
+#define MX25_INT_CSPI2         13
+#define MX25_INT_CSPI1         14
+#define MX25_INT_CSI           17
+#define MX25_INT_UART3         18
+#define MX25_INT_KPP           24
+#define MX25_INT_DRYICE                25
+#define MX25_INT_UART2         32
+#define MX25_INT_NANDFC                33
+#define MX25_INT_LCDC          39
+#define MX25_INT_UART5         40
+#define MX25_INT_CAN1          43
+#define MX25_INT_CAN2          44
+#define MX25_INT_UART1         45
+#define MX25_INT_FEC           57
 
 #endif /* ifndef __MACH_MX25_H__ */
index bae9cd75beee333f097edc45a772add44f5d1d7c..a8ab2e02a8caf36460591865237e6d6c34d534de 100644 (file)
@@ -48,7 +48,7 @@
 #define MX27_CSPI2_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x0f000)
 #define MX27_SSI1_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x10000)
 #define MX27_SSI2_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x11000)
-#define MX27_I2C_BASE_ADDR                     (MX27_AIPI_BASE_ADDR + 0x12000)
+#define MX27_I2C1_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x12000)
 #define MX27_SDHC1_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x13000)
 #define MX27_SDHC2_BASE_ADDR                   (MX27_AIPI_BASE_ADDR + 0x14000)
 #define MX27_GPIO_BASE_ADDR                    (MX27_AIPI_BASE_ADDR + 0x15000)
@@ -150,7 +150,7 @@ static inline void mx27_setup_weimcs(size_t cs,
 #define MX27_INT_SDHC3         9
 #define MX27_INT_SDHC2         10
 #define MX27_INT_SDHC1         11
-#define MX27_INT_I2C           12
+#define MX27_INT_I2C1          12
 #define MX27_INT_SSI2          13
 #define MX27_INT_SSI1          14
 #define MX27_INT_CSPI2         15
diff --git a/arch/arm/plat-mxc/include/mach/mx2_cam.h b/arch/arm/plat-mxc/include/mach/mx2_cam.h
new file mode 100644 (file)
index 0000000..3c080a3
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * mx2-cam.h - i.MX27/i.MX25 camera driver header file
+ *
+ * Copyright (C) 2003, Intel Corporation
+ * Copyright (C) 2008, Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2010, Baruch Siach <baruch@tkos.co.il>
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __MACH_MX2_CAM_H_
+#define __MACH_MX2_CAM_H_
+
+#define MX2_CAMERA_SWAP16              (1 << 0)
+#define MX2_CAMERA_EXT_VSYNC           (1 << 1)
+#define MX2_CAMERA_CCIR                        (1 << 2)
+#define MX2_CAMERA_CCIR_INTERLACE      (1 << 3)
+#define MX2_CAMERA_HSYNC_HIGH          (1 << 4)
+#define MX2_CAMERA_GATED_CLOCK         (1 << 5)
+#define MX2_CAMERA_INV_DATA            (1 << 6)
+#define MX2_CAMERA_PCLK_SAMPLE_RISING  (1 << 7)
+#define MX2_CAMERA_PACK_DIR_MSB                (1 << 8)
+
+/**
+ * struct mx2_camera_platform_data - optional platform data for mx2_camera
+ * @flags: any combination of MX2_CAMERA_*
+ * @clk: clock rate of the csi block / 2
+ */
+struct mx2_camera_platform_data {
+       unsigned long flags;
+       unsigned long clk;
+};
+
+#endif /* __MACH_MX2_CAM_H_ */
index fb90e119c2b5db473a3d4e01ef48dd6a76921493..afee3ab9d62e2aef32a366f21c82350a562dab22 100644 (file)
@@ -23,7 +23,7 @@
 #define MX31_ETB_SLOT4_BASE_ADDR               (MX31_AIPS1_BASE_ADDR + 0x10000)
 #define MX31_ETB_SLOT5_BASE_ADDR               (MX31_AIPS1_BASE_ADDR + 0x14000)
 #define MX31_ECT_CTIO_BASE_ADDR                        (MX31_AIPS1_BASE_ADDR + 0x18000)
-#define MX31_I2C_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x80000)
+#define MX31_I2C1_BASE_ADDR                    (MX31_AIPS1_BASE_ADDR + 0x80000)
 #define MX31_I2C3_BASE_ADDR                    (MX31_AIPS1_BASE_ADDR + 0x84000)
 #define MX31_OTG_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x88000)
 #define MX31_ATA_BASE_ADDR                     (MX31_AIPS1_BASE_ADDR + 0x8c000)
@@ -145,7 +145,7 @@ static inline void mx31_setup_weimcs(size_t cs,
 #define MX31_INT_FIRI          7
 #define MX31_INT_MMC_SDHC2     8
 #define MX31_INT_MMC_SDHC1     9
-#define MX31_INT_I2C           10
+#define MX31_INT_I2C1          10
 #define MX31_INT_SSI2          11
 #define MX31_INT_SSI1          12
 #define MX31_INT_CSPI2         13
index 526a55842ae53d6719a1221f4d8b3ccc33a75429..af3038c12e39c03b16d00855e5f5f40b75ba9b97 100644 (file)
@@ -18,7 +18,7 @@
 #define MX35_ETB_SLOT4_BASE_ADDR               (MX35_AIPS1_BASE_ADDR + 0x10000)
 #define MX35_ETB_SLOT5_BASE_ADDR               (MX35_AIPS1_BASE_ADDR + 0x14000)
 #define MX35_ECT_CTIO_BASE_ADDR                        (MX35_AIPS1_BASE_ADDR + 0x18000)
-#define MX35_I2C_BASE_ADDR                     (MX35_AIPS1_BASE_ADDR + 0x80000)
+#define MX35_I2C1_BASE_ADDR                    (MX35_AIPS1_BASE_ADDR + 0x80000)
 #define MX35_I2C3_BASE_ADDR                    (MX35_AIPS1_BASE_ADDR + 0x84000)
 #define MX35_UART1_BASE_ADDR                   (MX35_AIPS1_BASE_ADDR + 0x90000)
 #define MX35_UART2_BASE_ADDR                   (MX35_AIPS1_BASE_ADDR + 0x94000)
@@ -60,6 +60,8 @@
 #define MX35_RTC_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xd8000)
 #define MX35_WDOG_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xdc000)
 #define MX35_PWM_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xe0000)
+#define MX35_CAN1_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xe4000)
+#define MX35_CAN2_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xe8000)
 #define MX35_RTIC_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xec000)
 #define MX35_OTG_BASE_ADDR             0x53ff4000
 
 #define MX35_INT_MMC_SDHC1     7
 #define MX35_INT_MMC_SDHC2     8
 #define MX35_INT_MMC_SDHC3     9
-#define MX35_INT_I2C           10
+#define MX35_INT_I2C1          10
 #define MX35_INT_SSI1          11
 #define MX35_INT_SSI2          12
 #define MX35_INT_CSPI2         13
index 36d7ff27b5e2244861cd7f4750d857e20c7c8fcf..f226ee3777e17368c7901ebfeddaca2d523acf1a 100644 (file)
  * 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 _MX3_CAMERA_H_
index 5182b986b7851e0d91513b37969312adf15d69de..0ca3101ebf36e92364b33a78fbf4e7db916f2af6 100644 (file)
  * 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 __MACH_MXC91231_H__
 #define __MACH_MXC91231_H__
index 5d2d21d414e0e71716ab8878a14548010faff253..04c0d060d8143ae4c60d526a6198178f2e02bccb 100644 (file)
 #ifndef __ASM_ARCH_NAND_H
 #define __ASM_ARCH_NAND_H
 
+#include <linux/mtd/partitions.h>
+
 struct mxc_nand_platform_data {
-       int width;      /* data bus width in bytes */
-       int hw_ecc:1;   /* 0 if supress hardware ECC */
-       int flash_bbt:1; /* set to 1 to use a flash based bbt */
+       unsigned int width;     /* data bus width in bytes */
+       unsigned int hw_ecc:1;  /* 0 if supress hardware ECC */
+       unsigned int flash_bbt:1; /* set to 1 to use a flash based bbt */
+       struct mtd_partition *parts;    /* partition table */
+       int nr_parts;                   /* size of parts */
 };
 #endif /* __ASM_ARCH_NAND_H */
index ef00199568de15f998571b3cd20a34a29ff56de7..4acd1143a9bdd7444c12ca547ed957b47ef302d6 100644 (file)
  * 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 __ASM_ARCH_MXC_SYSTEM_H__
index 024416ed11cd9673bf5bf478f17412c81f6e98c8..2d9624697cc9c9e7d99c5733e5e750b90c0a592b 100644 (file)
  * 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 __ASM_ARCH_MXC_TIMEX_H__
index b6d3d0fddc48aebb62763c2d364bed0103909063..d9bd37e4667a23f04e3f20ba0fd4fcd8f599b6d6 100644 (file)
  * 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 __ASM_ARCH_MXC_UNCOMPRESS_H__
 #define __ASM_ARCH_MXC_UNCOMPRESS_H__
index 44243a278434b027d604ed590e43d9cdb5749653..ef6379c474be8a66656583cca426bd7b23386f6a 100644 (file)
  * 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 __ASM_ARCH_MXC_VMALLOC_H__
index 778ddfe57d895c5db1a4969886bd1dac6226f5f0..7331f2ace5fe12b49e1ce431fd01459bc6bae785 100644 (file)
@@ -142,9 +142,6 @@ void __init mxc_init_irq(void __iomem *irqbase)
        for (i = 0; i < 8; i++)
                __raw_writel(0, avic_base + AVIC_NIPRIORITY(i));
 
-       /* init architectures chained interrupt handler */
-       mxc_register_gpios();
-
 #ifdef CONFIG_FIQ
        /* Initialize FIQ */
        init_FIQ();
index 97f42799fa589caae5f1c99ebc11670ee16f93a3..925bce4607e78bc91f2fb4605e4c8d5195027ff2 100644 (file)
  * 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>
index 9b86d2a60d43789a22d644105981815169123dd7..b3da9aad4295704ef9ea8a4a43c95127d74e6d9e 100644 (file)
@@ -145,8 +145,6 @@ void __init tzic_init_irq(void __iomem *irqbase)
                set_irq_handler(i, handle_level_irq);
                set_irq_flags(i, IRQF_VALID);
        }
-       mxc_register_gpios();
-
        pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
 }
 
index 5a6ef252c38b37732d36e8dc52c97b96d9385604..977c8f9a07a2194322deada32da2afd0481d50ad 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 
+#include <plat/pincfg.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
 
@@ -46,28 +47,217 @@ struct nmk_gpio_chip {
        u32 edge_falling;
 };
 
+static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
+                               unsigned offset, int gpio_mode)
+{
+       u32 bit = 1 << offset;
+       u32 afunc, bfunc;
+
+       afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
+       bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
+       if (gpio_mode & NMK_GPIO_ALT_A)
+               afunc |= bit;
+       if (gpio_mode & NMK_GPIO_ALT_B)
+               bfunc |= bit;
+       writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
+       writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
+}
+
+static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip,
+                               unsigned offset, enum nmk_gpio_slpm mode)
+{
+       u32 bit = 1 << offset;
+       u32 slpm;
+
+       slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC);
+       if (mode == NMK_GPIO_SLPM_NOCHANGE)
+               slpm |= bit;
+       else
+               slpm &= ~bit;
+       writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC);
+}
+
+static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
+                               unsigned offset, enum nmk_gpio_pull pull)
+{
+       u32 bit = 1 << offset;
+       u32 pdis;
+
+       pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
+       if (pull == NMK_GPIO_PULL_NONE)
+               pdis |= bit;
+       else
+               pdis &= ~bit;
+       writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
+
+       if (pull == NMK_GPIO_PULL_UP)
+               writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
+       else if (pull == NMK_GPIO_PULL_DOWN)
+               writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
+                                 unsigned offset)
+{
+       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
+}
+
+static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
+                            pin_cfg_t cfg)
+{
+       static const char *afnames[] = {
+               [NMK_GPIO_ALT_GPIO]     = "GPIO",
+               [NMK_GPIO_ALT_A]        = "A",
+               [NMK_GPIO_ALT_B]        = "B",
+               [NMK_GPIO_ALT_C]        = "C"
+       };
+       static const char *pullnames[] = {
+               [NMK_GPIO_PULL_NONE]    = "none",
+               [NMK_GPIO_PULL_UP]      = "up",
+               [NMK_GPIO_PULL_DOWN]    = "down",
+               [3] /* illegal */       = "??"
+       };
+       static const char *slpmnames[] = {
+               [NMK_GPIO_SLPM_INPUT]           = "input",
+               [NMK_GPIO_SLPM_NOCHANGE]        = "no-change",
+       };
+
+       int pin = PIN_NUM(cfg);
+       int pull = PIN_PULL(cfg);
+       int af = PIN_ALT(cfg);
+       int slpm = PIN_SLPM(cfg);
+
+       dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s\n",
+               pin, afnames[af], pullnames[pull], slpmnames[slpm]);
+
+       __nmk_gpio_make_input(nmk_chip, offset);
+       __nmk_gpio_set_pull(nmk_chip, offset, pull);
+       __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
+       __nmk_gpio_set_mode(nmk_chip, offset, af);
+}
+
+/**
+ * nmk_config_pin - configure a pin's mux attributes
+ * @cfg: pin confguration
+ *
+ * Configures a pin's mode (alternate function or GPIO), its pull up status,
+ * and its sleep mode based on the specified configuration.  The @cfg is
+ * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
+ * are constructed using, and can be further enhanced with, the macros in
+ * plat/pincfg.h.
+ *
+ * If a pin's mode is set to GPIO, it is configured as an input to avoid
+ * side-effects.  The gpio can be manipulated later using standard GPIO API
+ * calls.
+ */
+int nmk_config_pin(pin_cfg_t cfg)
+{
+       struct nmk_gpio_chip *nmk_chip;
+       int gpio = PIN_NUM(cfg);
+       unsigned long flags;
+
+       nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+       if (!nmk_chip)
+               return -EINVAL;
+
+       spin_lock_irqsave(&nmk_chip->lock, flags);
+       __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg);
+       spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(nmk_config_pin);
+
+/**
+ * nmk_config_pins - configure several pins at once
+ * @cfgs: array of pin configurations
+ * @num: number of elments in the array
+ *
+ * Configures several pins using nmk_config_pin().  Refer to that function for
+ * further information.
+ */
+int nmk_config_pins(pin_cfg_t *cfgs, int num)
+{
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < num; i++) {
+               int ret = nmk_config_pin(cfgs[i]);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(nmk_config_pins);
+
+/**
+ * nmk_gpio_set_slpm() - configure the sleep mode of a pin
+ * @gpio: pin number
+ * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
+ *
+ * Sets the sleep mode of a pin.  If @mode is NMK_GPIO_SLPM_INPUT, the pin is
+ * changed to an input (with pullup/down enabled) in sleep and deep sleep.  If
+ * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
+ * configured even when in sleep and deep sleep.
+ */
+int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
+{
+       struct nmk_gpio_chip *nmk_chip;
+       unsigned long flags;
+
+       nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+       if (!nmk_chip)
+               return -EINVAL;
+
+       spin_lock_irqsave(&nmk_chip->lock, flags);
+       __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
+       spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+       return 0;
+}
+
+/**
+ * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
+ * @gpio: pin number
+ * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
+ *
+ * Enables/disables pull up/down on a specified pin.  This only takes effect if
+ * the pin is configured as an input (either explicitly or by the alternate
+ * function).
+ *
+ * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
+ * configured as an input.  Otherwise, due to the way the controller registers
+ * work, this function will change the value output on the pin.
+ */
+int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
+{
+       struct nmk_gpio_chip *nmk_chip;
+       unsigned long flags;
+
+       nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+       if (!nmk_chip)
+               return -EINVAL;
+
+       spin_lock_irqsave(&nmk_chip->lock, flags);
+       __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
+       spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+       return 0;
+}
+
 /* Mode functions */
 int nmk_gpio_set_mode(int gpio, int gpio_mode)
 {
        struct nmk_gpio_chip *nmk_chip;
        unsigned long flags;
-       u32 afunc, bfunc, bit;
 
        nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
        if (!nmk_chip)
                return -EINVAL;
 
-       bit = 1 << (gpio - nmk_chip->chip.base);
-
        spin_lock_irqsave(&nmk_chip->lock, flags);
-       afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
-       bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
-       if (gpio_mode & NMK_GPIO_ALT_A)
-               afunc |= bit;
-       if (gpio_mode & NMK_GPIO_ALT_B)
-               bfunc |= bit;
-       writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
-       writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
+       __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
        spin_unlock_irqrestore(&nmk_chip->lock, flags);
 
        return 0;
@@ -111,32 +301,41 @@ static void nmk_gpio_irq_ack(unsigned int irq)
        writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
 }
 
+enum nmk_gpio_irq_type {
+       NORMAL,
+       WAKE,
+};
+
 static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
-                                 int gpio, bool enable)
+                                 int gpio, enum nmk_gpio_irq_type which,
+                                 bool enable)
 {
+       u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
+       u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
        u32 bitmask = nmk_gpio_get_bitmask(gpio);
        u32 reg;
 
        /* we must individually set/clear the two edges */
        if (nmk_chip->edge_rising & bitmask) {
-               reg = readl(nmk_chip->addr + NMK_GPIO_RIMSC);
+               reg = readl(nmk_chip->addr + rimsc);
                if (enable)
                        reg |= bitmask;
                else
                        reg &= ~bitmask;
-               writel(reg, nmk_chip->addr + NMK_GPIO_RIMSC);
+               writel(reg, nmk_chip->addr + rimsc);
        }
        if (nmk_chip->edge_falling & bitmask) {
-               reg = readl(nmk_chip->addr + NMK_GPIO_FIMSC);
+               reg = readl(nmk_chip->addr + fimsc);
                if (enable)
                        reg |= bitmask;
                else
                        reg &= ~bitmask;
-               writel(reg, nmk_chip->addr + NMK_GPIO_FIMSC);
+               writel(reg, nmk_chip->addr + fimsc);
        }
 }
 
-static void nmk_gpio_irq_modify(unsigned int irq, bool enable)
+static int nmk_gpio_irq_modify(unsigned int irq, enum nmk_gpio_irq_type which,
+                              bool enable)
 {
        int gpio;
        struct nmk_gpio_chip *nmk_chip;
@@ -147,26 +346,35 @@ static void nmk_gpio_irq_modify(unsigned int irq, bool enable)
        nmk_chip = get_irq_chip_data(irq);
        bitmask = nmk_gpio_get_bitmask(gpio);
        if (!nmk_chip)
-               return;
+               return -EINVAL;
 
        spin_lock_irqsave(&nmk_chip->lock, flags);
-       __nmk_gpio_irq_modify(nmk_chip, gpio, enable);
+       __nmk_gpio_irq_modify(nmk_chip, gpio, which, enable);
        spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+       return 0;
 }
 
 static void nmk_gpio_irq_mask(unsigned int irq)
 {
-       nmk_gpio_irq_modify(irq, false);
-};
+       nmk_gpio_irq_modify(irq, NORMAL, false);
+}
 
 static void nmk_gpio_irq_unmask(unsigned int irq)
 {
-       nmk_gpio_irq_modify(irq, true);
+       nmk_gpio_irq_modify(irq, NORMAL, true);
+}
+
+static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+       return nmk_gpio_irq_modify(irq, WAKE, on);
 }
 
 static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
 {
-       bool enabled = !(irq_to_desc(irq)->status & IRQ_DISABLED);
+       struct irq_desc *desc = irq_to_desc(irq);
+       bool enabled = !(desc->status & IRQ_DISABLED);
+       bool wake = desc->wake_depth;
        int gpio;
        struct nmk_gpio_chip *nmk_chip;
        unsigned long flags;
@@ -186,7 +394,10 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
        spin_lock_irqsave(&nmk_chip->lock, flags);
 
        if (enabled)
-               __nmk_gpio_irq_modify(nmk_chip, gpio, false);
+               __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
+
+       if (wake)
+               __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
 
        nmk_chip->edge_rising &= ~bitmask;
        if (type & IRQ_TYPE_EDGE_RISING)
@@ -197,7 +408,10 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
                nmk_chip->edge_falling |= bitmask;
 
        if (enabled)
-               __nmk_gpio_irq_modify(nmk_chip, gpio, true);
+               __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
+
+       if (wake)
+               __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
 
        spin_unlock_irqrestore(&nmk_chip->lock, flags);
 
@@ -210,6 +424,7 @@ static struct irq_chip nmk_gpio_irq_chip = {
        .mask           = nmk_gpio_irq_mask,
        .unmask         = nmk_gpio_irq_unmask,
        .set_type       = nmk_gpio_irq_set_type,
+       .set_wake       = nmk_gpio_irq_set_wake,
 };
 
 static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -266,16 +481,6 @@ static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
        return 0;
 }
 
-static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
-                               int val)
-{
-       struct nmk_gpio_chip *nmk_chip =
-               container_of(chip, struct nmk_gpio_chip, chip);
-
-       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
-       return 0;
-}
-
 static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
 {
        struct nmk_gpio_chip *nmk_chip =
@@ -298,12 +503,33 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
                writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
 }
 
+static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
+                               int val)
+{
+       struct nmk_gpio_chip *nmk_chip =
+               container_of(chip, struct nmk_gpio_chip, chip);
+
+       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+       nmk_gpio_set_output(chip, offset, val);
+
+       return 0;
+}
+
+static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct nmk_gpio_chip *nmk_chip =
+               container_of(chip, struct nmk_gpio_chip, chip);
+
+       return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
+}
+
 /* This structure is replicated for each GPIO block allocated at probe time */
 static struct gpio_chip nmk_gpio_template = {
        .direction_input        = nmk_gpio_make_input,
        .get                    = nmk_gpio_get_input,
        .direction_output       = nmk_gpio_make_output,
        .set                    = nmk_gpio_set_output,
+       .to_irq                 = nmk_gpio_to_irq,
        .ngpio                  = NMK_GPIO_PER_CHIP,
        .can_sleep              = 0,
 };
@@ -393,30 +619,12 @@ out:
        return ret;
 }
 
-static int __exit nmk_gpio_remove(struct platform_device *dev)
-{
-       struct nmk_gpio_chip *nmk_chip;
-       struct resource *res;
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-
-       nmk_chip = platform_get_drvdata(dev);
-       gpiochip_remove(&nmk_chip->chip);
-       clk_disable(nmk_chip->clk);
-       clk_put(nmk_chip->clk);
-       kfree(nmk_chip);
-       release_mem_region(res->start, resource_size(res));
-       return 0;
-}
-
-
 static struct platform_driver nmk_gpio_driver = {
        .driver = {
                .owner = THIS_MODULE,
                .name = "gpio",
                },
        .probe = nmk_gpio_probe,
-       .remove = __exit_p(nmk_gpio_remove),
        .suspend = NULL, /* to be done */
        .resume = NULL,
 };
@@ -426,7 +634,7 @@ static int __init nmk_gpio_init(void)
        return platform_driver_register(&nmk_gpio_driver);
 }
 
-arch_initcall(nmk_gpio_init);
+core_initcall(nmk_gpio_init);
 
 MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
 MODULE_DESCRIPTION("Nomadik GPIO Driver");
index 4200811249ca25180e9b2357ed58140f17cb9cd4..aba355101f492687e39e303fff8b26ceb761541e 100644 (file)
 #define NMK_GPIO_ALT_B 2
 #define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B)
 
+/* Pull up/down values */
+enum nmk_gpio_pull {
+       NMK_GPIO_PULL_NONE,
+       NMK_GPIO_PULL_UP,
+       NMK_GPIO_PULL_DOWN,
+};
+
+/* Sleep mode */
+enum nmk_gpio_slpm {
+       NMK_GPIO_SLPM_INPUT,
+       NMK_GPIO_SLPM_NOCHANGE,
+};
+
+extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
+extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
 extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
 extern int nmk_gpio_get_mode(int gpio);
 
index 42c907258b14a04e34622d1ca99c638c5827631f..65704a3d42410890b044fd499cfba2ceaf067b9c 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef __PLAT_MTU_H
 #define __PLAT_MTU_H
 
+/*
+ * Guaranteed runtime conversion range in seconds for
+ * the clocksource and clockevent.
+ */
+#define MTU_MIN_RANGE 4
+
 /* should be set by the platform code */
 extern void __iomem *mtu_base;
 
diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h
new file mode 100644 (file)
index 0000000..7eed11c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ *
+ * Based on arch/arm/mach-pxa/include/mach/mfp.h:
+ *   Copyright (C) 2007 Marvell International Ltd.
+ *   eric miao <eric.miao@marvell.com>
+ */
+
+#ifndef __PLAT_PINCFG_H
+#define __PLAT_PINCFG_H
+
+/*
+ * pin configurations are represented by 32-bit integers:
+ *
+ *     bit  0.. 8 - Pin Number (512 Pins Maximum)
+ *     bit  9..10 - Alternate Function Selection
+ *     bit 11..12 - Pull up/down state
+ *     bit     13 - Sleep mode behaviour
+ *
+ * to facilitate the definition, the following macros are provided
+ *
+ * PIN_CFG_DEFAULT - default config (0):
+ *                  pull up/down = disabled
+ *                  sleep mode = input
+ *
+ * PIN_CFG        - default config with alternate function
+ * PIN_CFG_PULL           - default config with alternate function and pull up/down
+ */
+
+typedef unsigned long pin_cfg_t;
+
+#define PIN_NUM_MASK           0x1ff
+#define PIN_NUM(x)             ((x) & PIN_NUM_MASK)
+
+#define PIN_ALT_SHIFT          9
+#define PIN_ALT_MASK           (0x3 << PIN_ALT_SHIFT)
+#define PIN_ALT(x)             (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT)
+#define PIN_GPIO               (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT)
+#define PIN_ALT_A              (NMK_GPIO_ALT_A << PIN_ALT_SHIFT)
+#define PIN_ALT_B              (NMK_GPIO_ALT_B << PIN_ALT_SHIFT)
+#define PIN_ALT_C              (NMK_GPIO_ALT_C << PIN_ALT_SHIFT)
+
+#define PIN_PULL_SHIFT         11
+#define PIN_PULL_MASK          (0x3 << PIN_PULL_SHIFT)
+#define PIN_PULL(x)            (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT)
+#define PIN_PULL_NONE          (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT)
+#define PIN_PULL_UP            (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT)
+#define PIN_PULL_DOWN          (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT)
+
+#define PIN_SLPM_SHIFT         13
+#define PIN_SLPM_MASK          (0x1 << PIN_SLPM_SHIFT)
+#define PIN_SLPM(x)            (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT)
+#define PIN_SLPM_INPUT         (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
+#define PIN_SLPM_NOCHANGE      (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT)
+
+#define PIN_CFG_DEFAULT                (PIN_PULL_NONE | PIN_SLPM_INPUT)
+
+#define PIN_CFG(num, alt)              \
+       (PIN_CFG_DEFAULT |\
+        (PIN_NUM(num) | PIN_##alt))
+
+#define PIN_CFG_PULL(num, alt, pull)   \
+       ((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\
+        (PIN_NUM(num) | PIN_##alt | PIN_PULL_##pull))
+
+extern int nmk_config_pin(pin_cfg_t cfg);
+extern int nmk_config_pins(pin_cfg_t *cfgs, int num);
+
+#endif
index 08aaa4a7f65fe0e868b1a8cbfa8dd80d73209cec..ea3ca86c52836ba1ec9fe780da9c1629db91723f 100644 (file)
@@ -42,7 +42,6 @@ static struct clocksource nmdk_clksrc = {
        .rating         = 200,
        .read           = nmdk_read_timer_dummy,
        .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = 20,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -82,6 +81,12 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_UNUSED:
                /* disable irq */
                writel(0, mtu_base + MTU_IMSC);
+               /* disable timer */
+               cr = readl(mtu_base + MTU_CR(1));
+               cr &= ~MTU_CRn_ENA;
+               writel(cr, mtu_base + MTU_CR(1));
+               /* load some high default value */
+               writel(0xffffffff, mtu_base + MTU_LR(1));
                break;
        case CLOCK_EVT_MODE_RESUME:
                break;
@@ -98,7 +103,6 @@ static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
 static struct clock_event_device nmdk_clkevt = {
        .name           = "mtu_1",
        .features       = CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 32,
        .rating         = 200,
        .set_mode       = nmdk_clkevt_mode,
        .set_next_event = nmdk_clkevt_next,
@@ -151,6 +155,7 @@ void __init nmdk_timer_init(void)
        } else {
                cr |= MTU_CRn_PRESCALE_1;
        }
+       clocksource_calc_mult_shift(&nmdk_clksrc, rate, MTU_MIN_RANGE);
 
        /* Timer 0 is the free running clocksource */
        writel(cr, mtu_base + MTU_CR(0));
@@ -158,7 +163,6 @@ void __init nmdk_timer_init(void)
        writel(0, mtu_base + MTU_BGLR(0));
        writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
 
-       nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
        /* Now the scheduling clock is ready */
        nmdk_clksrc.read = nmdk_read_timer;
 
@@ -175,8 +179,10 @@ void __init nmdk_timer_init(void)
        } else {
                cr |= MTU_CRn_PRESCALE_1;
        }
+       clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
+
        writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
-       nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
+
        nmdk_clkevt.max_delta_ns =
                clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
        nmdk_clkevt.min_delta_ns =
index 219c01e82bc5a3cf70055f5e7593b0c115000e21..ebed82699eb2625b87898b6fcbc6f75bd44a9325 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/omapfb.h>
 
 #include <mach/hardware.h>
 #include <asm/system.h>
@@ -35,6 +36,7 @@
 #include <plat/mux.h>
 #include <plat/fpga.h>
 #include <plat/serial.h>
+#include <plat/vram.h>
 
 #include <plat/clock.h>
 
@@ -81,6 +83,12 @@ const void *omap_get_var_config(u16 tag, size_t *len)
 }
 EXPORT_SYMBOL(omap_get_var_config);
 
+void __init omap_reserve(void)
+{
+       omapfb_reserve_sdram_memblock();
+       omap_vram_reserve_sdram_memblock();
+}
+
 /*
  * 32KHz clocksource ... always available, on pretty most chips except
  * OMAP 730 and 1510.  Other timers could be used as clocksources, with
index d3eea4f47533050618ce2a0e489a79f5f2725088..0054b9501a53976a384cde437b43be7c03cc582a 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/io.h>
 #include <linux/omapfb.h>
 
@@ -171,49 +171,78 @@ static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg,
        return 0;
 }
 
+static int valid_sdram(unsigned long addr, unsigned long size)
+{
+       struct memblock_property res;
+
+       res.base = addr;
+       res.size = size;
+       return !memblock_find(&res) && res.base == addr && res.size == size;
+}
+
+static int reserve_sdram(unsigned long addr, unsigned long size)
+{
+       if (memblock_is_region_reserved(addr, size))
+               return -EBUSY;
+       if (memblock_reserve(addr, size))
+               return -ENOMEM;
+       return 0;
+}
+
 /*
  * Called from map_io. We need to call to this early enough so that we
  * can reserve the fixed SDRAM regions before VM could get hold of them.
  */
-void __init omapfb_reserve_sdram(void)
+void __init omapfb_reserve_sdram_memblock(void)
 {
-       struct bootmem_data     *bdata;
-       unsigned long           sdram_start, sdram_size;
-       unsigned long           reserved;
-       int                     i;
+       unsigned long reserved = 0;
+       int i;
 
        if (config_invalid)
                return;
 
-       bdata = NODE_DATA(0)->bdata;
-       sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
-       sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
-       reserved = 0;
        for (i = 0; ; i++) {
-               struct omapfb_mem_region        rg;
+               struct omapfb_mem_region rg;
 
                if (get_fbmem_region(i, &rg) < 0)
                        break;
+
                if (i == OMAPFB_PLANE_NUM) {
-                       printk(KERN_ERR
-                               "Extraneous FB mem configuration entries\n");
+                       pr_err("Extraneous FB mem configuration entries\n");
                        config_invalid = 1;
                        return;
                }
+
                /* Check if it's our memory type. */
-               if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SDRAM,
-                                         sdram_start, sdram_size) < 0 ||
-                   (rg.type != OMAPFB_MEMTYPE_SDRAM))
+               if (rg.type != OMAPFB_MEMTYPE_SDRAM)
                        continue;
-               BUG_ON(omapfb_config.mem_desc.region[i].size);
-               if (check_fbmem_region(i, &rg, sdram_start, sdram_size) < 0) {
+
+               /* Check if the region falls within SDRAM */
+               if (rg.paddr && !valid_sdram(rg.paddr, rg.size))
+                       continue;
+
+               if (rg.size == 0) {
+                       pr_err("Zero size for FB region %d\n", i);
                        config_invalid = 1;
                        return;
                }
+
                if (rg.paddr) {
-                       reserve_bootmem(rg.paddr, rg.size, BOOTMEM_DEFAULT);
+                       if (reserve_sdram(rg.paddr, rg.size)) {
+                               pr_err("Trying to use reserved memory for FB region %d\n",
+                                       i);
+                               config_invalid = 1;
+                               return;
+                       }
                        reserved += rg.size;
                }
+
+               if (omapfb_config.mem_desc.region[i].size) {
+                       pr_err("FB region %d already set\n", i);
+                       config_invalid = 1;
+                       return;
+               }
+
                omapfb_config.mem_desc.region[i] = rg;
                configured_regions++;
        }
@@ -359,7 +388,10 @@ static inline int omap_init_fb(void)
 
 arch_initcall(omap_init_fb);
 
-void omapfb_reserve_sdram(void) {}
+void omapfb_reserve_sdram_memblock(void)
+{
+}
+
 unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
                                  unsigned long sram_vstart,
                                  unsigned long sram_size,
@@ -375,7 +407,10 @@ void omapfb_set_platform_data(struct omapfb_platform_data *data)
 {
 }
 
-void omapfb_reserve_sdram(void) {}
+void omapfb_reserve_sdram_memblock(void)
+{
+}
+
 unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
                                  unsigned long sram_vstart,
                                  unsigned long sram_size,
index d265018f5e6b729a146a351388f3213dc8c72472..5e4afbee0fd7812e2fe907b67fb7abaab0fb34fa 100644 (file)
@@ -34,6 +34,8 @@ struct sys_timer;
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 
+extern void omap_reserve(void);
+
 /*
  * IO bases for various OMAP processors
  * Except the tap base, rest all the io bases
index edd4987758a64db91d606a26806593ae2a48d698..0aa4ecd12c7d5768f74efa2d4e7977f729e2338d 100644 (file)
@@ -38,7 +38,7 @@ extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
 extern void omap_vram_set_sdram_vram(u32 size, u32 start);
 extern void omap_vram_set_sram_vram(u32 size, u32 start);
 
-extern void omap_vram_reserve_sdram(void);
+extern void omap_vram_reserve_sdram_memblock(void);
 extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
                                            unsigned long sram_vstart,
                                            unsigned long sram_size,
@@ -48,7 +48,7 @@ extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
 static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
 static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
 
-static inline void omap_vram_reserve_sdram(void) { }
+static inline void omap_vram_reserve_sdram_memblock(void) { }
 static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
                                            unsigned long sram_vstart,
                                            unsigned long sram_size,
index 54c84a492a0f0ab95de7ffa1590e0c5cf5259dc1..779553a1595e938ead6a4764e84ee8d87087acb9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mbus.h>
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
+#include <linux/delay.h>
 
 /*
  * PCIe unit register offsets.
@@ -46,6 +47,8 @@
 #define  PCIE_STAT_BUS_OFFS            8
 #define  PCIE_STAT_BUS_MASK            0xff
 #define  PCIE_STAT_LINK_DOWN           1
+#define PCIE_DEBUG_CTRL         0x1a60
+#define  PCIE_DEBUG_SOFT_RESET         (1<<20)
 
 
 u32 __init orion_pcie_dev_id(void __iomem *base)
@@ -85,6 +88,32 @@ void __init orion_pcie_set_local_bus_nr(void __iomem *base, int nr)
        writel(stat, base + PCIE_STAT_OFF);
 }
 
+void __init orion_pcie_reset(void __iomem *base)
+{
+       u32 reg;
+       int i;
+
+       /*
+        * MV-S104860-U0, Rev. C:
+        * PCI Express Unit Soft Reset
+        * When set, generates an internal reset in the PCI Express unit.
+        * This bit should be cleared after the link is re-established.
+        */
+       reg = readl(base + PCIE_DEBUG_CTRL);
+       reg |= PCIE_DEBUG_SOFT_RESET;
+       writel(reg, base + PCIE_DEBUG_CTRL);
+
+       for (i = 0; i < 20; i++) {
+               mdelay(10);
+
+               if (orion_pcie_link_up(base))
+                       break;
+       }
+
+       reg &= ~(PCIE_DEBUG_SOFT_RESET);
+       writel(reg, base + PCIE_DEBUG_CTRL);
+}
+
 /*
  * Setup PCIE BARs and Address Decode Wins:
  * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
@@ -152,6 +181,11 @@ void __init orion_pcie_setup(void __iomem *base,
        u16 cmd;
        u32 mask;
 
+       /*
+        * soft reset PCIe unit
+        */
+       orion_pcie_reset(base);
+
        /*
         * Point PCIe unit MBUS decode windows to DRAM space.
         */
diff --git a/arch/arm/plat-samsung/include/plat/keypad.h b/arch/arm/plat-samsung/include/plat/keypad.h
new file mode 100644 (file)
index 0000000..3a70c12
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Samsung Platform - Keypad platform data definitions
+ *
+ * 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 __PLAT_SAMSUNG_KEYPAD_H
+#define __PLAT_SAMSUNG_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+#define SAMSUNG_MAX_ROWS       8
+#define SAMSUNG_MAX_COLS       8
+
+/**
+ * struct samsung_keypad_platdata - Platform device data for Samsung Keypad.
+ * @keymap_data: pointer to &matrix_keymap_data.
+ * @rows: number of keypad row supported.
+ * @cols: number of keypad col supported.
+ * @no_autorepeat: disable key autorepeat.
+ * @wakeup: controls whether the device should be set up as wakeup source.
+ * @cfg_gpio: configure the GPIO.
+ *
+ * Initialisation data specific to either the machine or the platform
+ * for the device driver to use or call-back when configuring gpio.
+ */
+struct samsung_keypad_platdata {
+       const struct matrix_keymap_data *keymap_data;
+       unsigned int rows;
+       unsigned int cols;
+       bool no_autorepeat;
+       bool wakeup;
+
+       void (*cfg_gpio)(unsigned int rows, unsigned int cols);
+};
+
+#endif /* __PLAT_SAMSUNG_KEYPAD_H */
index a1025d38f38370ddcb769898cf3854bdab2bbe29..ab211652e4ca79d3e814bc9967cdace8d10edf7c 100644 (file)
 
 #define INT_STATUS             0x1
 
+/*
+ * Minimum clocksource/clockevent timer range in seconds
+ */
+#define SPEAR_MIN_RANGE 4
+
 static __iomem void *gpt_base;
 static struct clk *gpt_clk;
 
@@ -66,44 +71,6 @@ static void clockevent_set_mode(enum clock_event_mode mode,
 static int clockevent_next_event(unsigned long evt,
                                 struct clock_event_device *clk_event_dev);
 
-/*
- * Following clocksource_set_clock and clockevent_set_clock picked
- * from arch/mips/kernel/time.c
- */
-
-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;
-}
-
-void __init 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;
-}
-
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
        return (cycle_t) readw(gpt_base + COUNT(CLKSRC));
@@ -138,7 +105,7 @@ static void spear_clocksource_init(void)
        val |= CTRL_ENABLE ;
        writew(val, gpt_base + CR(CLKSRC));
 
-       clocksource_set_clock(&clksrc, tick_rate);
+       clocksource_calc_mult_shift(&clksrc, tick_rate, SPEAR_MIN_RANGE);
 
        /* register the clocksource */
        clocksource_register(&clksrc);
@@ -233,7 +200,7 @@ static void __init spear_clockevent_init(void)
        tick_rate = clk_get_rate(gpt_clk);
        tick_rate >>= CTRL_PRESCALER16;
 
-       clockevent_set_clock(&clkevt, tick_rate);
+       clockevents_calc_mult_shift(&clkevt, tick_rate, SPEAR_MIN_RANGE);
 
        clkevt.max_delta_ns = clockevent_delta2ns(0xfff0,
                        &clkevt);
index 9b1a66816aa652d97460bca5feafe5ec97069d61..5cf88e8427b15e66aafa287f1960e937a26fb89a 100644 (file)
@@ -2,3 +2,7 @@ obj-y   := clock.o
 obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
 obj-$(CONFIG_ARCH_REALVIEW) += sched-clock.o
 obj-$(CONFIG_ARCH_VERSATILE) += sched-clock.o
+ifeq ($(CONFIG_LEDS_CLASS),y)
+obj-$(CONFIG_ARCH_REALVIEW) += leds.o
+obj-$(CONFIG_ARCH_VERSATILE) += leds.o
+endif
diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c
new file mode 100644 (file)
index 0000000..3169fa5
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Driver for the 8 user LEDs found on the RealViews and Versatiles
+ * Based on DaVinci's DM365 board code
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Linus Walleij <triad@df.lth.se>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#ifdef VERSATILE_SYS_BASE
+#define LEDREG (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
+#endif
+
+#ifdef REALVIEW_SYS_BASE
+#define LEDREG (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
+#endif
+
+struct versatile_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} versatile_leds[] = {
+       { "versatile:0", "heartbeat", },
+       { "versatile:1", "mmc0", },
+       { "versatile:2", },
+       { "versatile:3", },
+       { "versatile:4", },
+       { "versatile:5", },
+       { "versatile:6", },
+       { "versatile:7", },
+};
+
+static void versatile_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
+{
+       struct versatile_led *led = container_of(cdev,
+                                                struct versatile_led, cdev);
+       u32 reg = readl(LEDREG);
+
+       if (b != LED_OFF)
+               reg |= led->mask;
+       else
+               reg &= ~led->mask;
+       writel(reg, LEDREG);
+}
+
+static enum led_brightness versatile_led_get(struct led_classdev *cdev)
+{
+       struct versatile_led *led = container_of(cdev,
+                                                struct versatile_led, cdev);
+       u32 reg = readl(LEDREG);
+
+       return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init versatile_leds_init(void)
+{
+       int i;
+
+       /* All ON */
+       writel(0xff, LEDREG);
+       for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) {
+               struct versatile_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = versatile_leds[i].name;
+               led->cdev.brightness_set = versatile_led_set;
+               led->cdev.brightness_get = versatile_led_get;
+               led->cdev.default_trigger = versatile_leds[i].trigger;
+               led->mask = BIT(i);
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(versatile_leds_init);
index 315a540c7ce50370757320350ed07322d0f3bd86..8063a322c790dd80b3c6b0719541d9e937c2a2bc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 
+#include <asm/cputype.h>
 #include <asm/thread_notify.h>
 #include <asm/vfp.h>
 
@@ -549,10 +550,13 @@ static int __init vfp_init(void)
                /*
                 * Check for the presence of the Advanced SIMD
                 * load/store instructions, integer and single
-                * precision floating point operations.
+                * precision floating point operations. Only check
+                * for NEON if the hardware has the MVFR registers.
                 */
-               if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
-                       elf_hwcap |= HWCAP_NEON;
+               if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
+                       if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
+                               elf_hwcap |= HWCAP_NEON;
+               }
 #endif
        }
        return 0;
index d5e3e60074472f8824f599d503c40744ad622ab0..bea9ee37ac9d2fc78cb9c5c7da4454bf529cb955 100644 (file)
@@ -535,8 +535,16 @@ pgm_no_vtime2:
        l       %r3,__LC_PGM_ILC        # load program interruption code
        la      %r8,0x7f
        nr      %r8,%r3                 # clear per-event-bit and ilc
-       be      BASED(pgm_exit)         # only per or per+check ?
-       b       BASED(pgm_do_call)
+       be      BASED(pgm_exit2)        # only per or per+check ?
+       l       %r7,BASED(.Ljump_table)
+       sll     %r8,2
+       l       %r7,0(%r8,%r7)          # load address of handler routine
+       la      %r2,SP_PTREGS(%r15)     # address of register-save area
+       basr    %r14,%r7                # branch to interrupt-handler
+pgm_exit2:
+       TRACE_IRQS_ON
+       stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
+       b       BASED(sysc_return)
 
 #
 # it was a single stepped SVC that is causing all the trouble
index e7192e1cb6785b24db347b2bbe2c22a469bdeb7d..8bccec15ea90086a557de590f90977d1e018cb4f 100644 (file)
@@ -544,8 +544,16 @@ pgm_no_vtime2:
        lgf     %r3,__LC_PGM_ILC        # load program interruption code
        lghi    %r8,0x7f
        ngr     %r8,%r3                 # clear per-event-bit and ilc
-       je      pgm_exit
-       j       pgm_do_call
+       je      pgm_exit2
+       sll     %r8,3
+       larl    %r1,pgm_check_table
+       lg      %r1,0(%r8,%r1)          # load address of handler routine
+       la      %r2,SP_PTREGS(%r15)     # address of register-save area
+       basr    %r14,%r1                # branch to interrupt-handler
+pgm_exit2:
+       TRACE_IRQS_ON
+       stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
+       j       sysc_return
 
 #
 # it was a single stepped SVC that is causing all the trouble
index a2163c95eb9845ffac908bf09b7af1bb5084cf3c..15a7536452d508b7998d37d9b679f4545d670dc1 100644 (file)
@@ -524,8 +524,11 @@ void etr_switch_to_local(void)
        if (!etr_eacr.sl)
                return;
        disable_sync_clock(NULL);
-       set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
-       queue_work(time_sync_wq, &etr_work);
+       if (!test_and_set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events)) {
+               etr_eacr.es = etr_eacr.sl = 0;
+               etr_setr(&etr_eacr);
+               queue_work(time_sync_wq, &etr_work);
+       }
 }
 
 /*
@@ -539,8 +542,11 @@ void etr_sync_check(void)
        if (!etr_eacr.es)
                return;
        disable_sync_clock(NULL);
-       set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
-       queue_work(time_sync_wq, &etr_work);
+       if (!test_and_set_bit(ETR_EVENT_SYNC_CHECK, &etr_events)) {
+               etr_eacr.es = 0;
+               etr_setr(&etr_eacr);
+               queue_work(time_sync_wq, &etr_work);
+       }
 }
 
 /*
@@ -902,7 +908,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib,
         * Do not try to get the alternate port aib if the clock
         * is not in sync yet.
         */
-       if (!check_sync_clock())
+       if (!eacr.es || !check_sync_clock())
                return eacr;
 
        /*
@@ -1064,7 +1070,7 @@ static void etr_work_fn(struct work_struct *work)
         * If the clock is in sync just update the eacr and return.
         * If there is no valid sync port wait for a port update.
         */
-       if (check_sync_clock() || sync_port < 0) {
+       if ((eacr.es && check_sync_clock()) || sync_port < 0) {
                etr_update_eacr(eacr);
                etr_set_tolec_timeout(now);
                goto out_unlock;
index 3a170bd3f3d06c1453b32e4ff544958859818ef2..de375b64e410e939a2a011d53a67ecfd97fc7d97 100644 (file)
@@ -316,7 +316,7 @@ static struct soc_camera_platform_info camera_info = {
        .format_name = "UYVY",
        .format_depth = 16,
        .format = {
-               .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+               .code = V4L2_MBUS_FMT_UYVY8_2X8,
                .colorspace = V4L2_COLORSPACE_SMPTE170M,
                .field = V4L2_FIELD_NONE,
                .width = 640,
index f60b2b6a0931d7d7279bfbfe7d29b3ac7ce6efea..d31590e7011bf895092535d15af5df6cc2e62df5 100644 (file)
@@ -122,6 +122,31 @@ static int __init amba_init(void)
 
 postcore_initcall(amba_init);
 
+static int amba_get_enable_pclk(struct amba_device *pcdev)
+{
+       struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
+       int ret;
+
+       pcdev->pclk = pclk;
+
+       if (IS_ERR(pclk))
+               return PTR_ERR(pclk);
+
+       ret = clk_enable(pclk);
+       if (ret)
+               clk_put(pclk);
+
+       return ret;
+}
+
+static void amba_put_disable_pclk(struct amba_device *pcdev)
+{
+       struct clk *pclk = pcdev->pclk;
+
+       clk_disable(pclk);
+       clk_put(pclk);
+}
+
 /*
  * These are the device model conversion veneers; they convert the
  * device model structures to our more specific structures.
@@ -130,17 +155,33 @@ static int amba_probe(struct device *dev)
 {
        struct amba_device *pcdev = to_amba_device(dev);
        struct amba_driver *pcdrv = to_amba_driver(dev->driver);
-       struct amba_id *id;
+       struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
+       int ret;
 
-       id = amba_lookup(pcdrv->id_table, pcdev);
+       do {
+               ret = amba_get_enable_pclk(pcdev);
+               if (ret)
+                       break;
+
+               ret = pcdrv->probe(pcdev, id);
+               if (ret == 0)
+                       break;
 
-       return pcdrv->probe(pcdev, id);
+               amba_put_disable_pclk(pcdev);
+       } while (0);
+
+       return ret;
 }
 
 static int amba_remove(struct device *dev)
 {
+       struct amba_device *pcdev = to_amba_device(dev);
        struct amba_driver *drv = to_amba_driver(dev->driver);
-       return drv->remove(to_amba_device(dev));
+       int ret = drv->remove(pcdev);
+
+       amba_put_disable_pclk(pcdev);
+
+       return ret;
 }
 
 static void amba_shutdown(struct device *dev)
@@ -203,7 +244,6 @@ static void amba_device_release(struct device *dev)
  */
 int amba_device_register(struct amba_device *dev, struct resource *parent)
 {
-       u32 pid, cid;
        u32 size;
        void __iomem *tmp;
        int i, ret;
@@ -241,25 +281,35 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
                goto err_release;
        }
 
-       /*
-        * Read pid and cid based on size of resource
-        * they are located at end of region
-        */
-       for (pid = 0, i = 0; i < 4; i++)
-               pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
-       for (cid = 0, i = 0; i < 4; i++)
-               cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
+       ret = amba_get_enable_pclk(dev);
+       if (ret == 0) {
+               u32 pid, cid;
 
-       iounmap(tmp);
+               /*
+                * Read pid and cid based on size of resource
+                * they are located at end of region
+                */
+               for (pid = 0, i = 0; i < 4; i++)
+                       pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
+                               (i * 8);
+               for (cid = 0, i = 0; i < 4; i++)
+                       cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
+                               (i * 8);
 
-       if (cid == 0xb105f00d)
-               dev->periphid = pid;
+               amba_put_disable_pclk(dev);
 
-       if (!dev->periphid) {
-               ret = -ENODEV;
-               goto err_release;
+               if (cid == 0xb105f00d)
+                       dev->periphid = pid;
+
+               if (!dev->periphid)
+                       ret = -ENODEV;
        }
 
+       iounmap(tmp);
+
+       if (ret)
+               goto err_release;
+
        ret = device_add(&dev->dev);
        if (ret)
                goto err_release;
index 54109dc9240ceb31581f060c8520d5e40c68bbf3..25be2102a60a064411f9955e6fe7c8339c2b2619 100644 (file)
@@ -1315,10 +1315,14 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
        if (test_bit(EV_SND, dev->evbit))
                return true;
 
-       if (test_bit(EV_KEY, dev->evbit))
+       if (test_bit(EV_KEY, dev->evbit)) {
                for (i = KEY_RESERVED; i < BTN_MISC; i++)
                        if (test_bit(i, dev->keybit))
                                return true;
+               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+       }
 
        return false;
 }
index ee568c8fcbd01db804dc071be08a1da4b5ee6e87..5005990f751f44e142bbe7ec11869bc45efd9772 100644 (file)
@@ -232,7 +232,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
        desc->chip->unmask(irq);
 }
 
-static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
+static int pl061_probe(struct amba_device *dev, struct amba_id *id)
 {
        struct pl061_platform_data *pdata;
        struct pl061_gpio *chip;
@@ -333,7 +333,7 @@ free_mem:
        return ret;
 }
 
-static struct amba_id pl061_ids[] __initdata = {
+static struct amba_id pl061_ids[] = {
        {
                .id     = 0x00041061,
                .mask   = 0x000fffff,
index c1981861bbbdb418ab58f9c9400e6c41a9430216..f87bf104df7a4cc79b2991759c88e00246cf64d4 100644 (file)
@@ -864,8 +864,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
                mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0,
                                    false);
                mode->hdisplay = 1366;
-               mode->vsync_start = mode->vsync_start - 1;
-               mode->vsync_end = mode->vsync_end - 1;
+               mode->hsync_start = mode->hsync_start - 1;
+               mode->hsync_end = mode->hsync_end - 1;
                return mode;
        }
 
index 115d26b762cc2b3db9301c86e66d97505f6fd291..3fa6984d9896094c3b0318ff486186c6cdf7ebdd 100644 (file)
@@ -333,6 +333,7 @@ static ssize_t radeon_get_pm_profile(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        (cp == PM_PROFILE_AUTO) ? "auto" :
                        (cp == PM_PROFILE_LOW) ? "low" :
+                       (cp == PM_PROFILE_MID) ? "mid" :
                        (cp == PM_PROFILE_HIGH) ? "high" : "default");
 }
 
index 866e54ec5fb2eed324a122fda7b05944b36392c0..b54a9a608ac2e605e36e2f4b1fadf93ff132fdf1 100644 (file)
@@ -1586,6 +1586,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
index 31601eef25dd660d649bc70b864e4db05340c955..8aee2577c1ade07a1b465ade90624dc88852929c 100644 (file)
 
 #define USB_VENDOR_ID_ETT              0x0664
 #define USB_DEVICE_ID_TC5UH            0x0309
+#define USB_DEVICE_ID_TC4UM            0x0306
 
 #define USB_VENDOR_ID_EZKEY            0x0518
 #define USB_DEVICE_ID_BTC_8193         0x0002
index 7a0d2e4661a1244b02de5b511389fc1ea7bb68d5..69d152e16a6aa2e0a51d3945473c78f9e8c2f7c7 100644 (file)
@@ -534,6 +534,9 @@ mapped:
                        input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
                else    input_set_abs_params(input, usage->code, a, b, 0, 0);
 
+               /* use a larger default input buffer for MT devices */
+               if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
+                       input_set_events_per_packet(input, 60);
        }
 
        if (usage->type == EV_ABS &&
index 2ee6c7a68bdccf4c9cf6c330f824d341f0a69302..054edf346e0b5f060e352572f473244e4aeeadcb 100644 (file)
@@ -10,7 +10,8 @@
 
 #define EVDEV_MINOR_BASE       64
 #define EVDEV_MINORS           32
-#define EVDEV_BUFFER_SIZE      64
+#define EVDEV_MIN_BUFFER_SIZE  64U
+#define EVDEV_BUF_PACKETS      8
 
 #include <linux/poll.h>
 #include <linux/sched.h>
@@ -23,7 +24,6 @@
 #include "input-compat.h"
 
 struct evdev {
-       int exist;
        int open;
        int minor;
        struct input_handle handle;
@@ -33,16 +33,18 @@ struct evdev {
        spinlock_t client_lock; /* protects client_list */
        struct mutex mutex;
        struct device dev;
+       bool exist;
 };
 
 struct evdev_client {
-       struct input_event buffer[EVDEV_BUFFER_SIZE];
        int head;
        int tail;
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
+       int bufsize;
+       struct input_event buffer[];
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -52,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client,
                             struct input_event *event)
 {
        /*
-        * Interrupts are disabled, just acquire the lock
+        * Interrupts are disabled, just acquire the lock.
+        * Make sure we don't leave with the client buffer
+        * "empty" by having client->head == client->tail.
         */
        spin_lock(&client->buffer_lock);
-       client->buffer[client->head++] = *event;
-       client->head &= EVDEV_BUFFER_SIZE - 1;
+       do {
+               client->buffer[client->head++] = *event;
+               client->head &= client->bufsize - 1;
+       } while (client->head == client->tail);
        spin_unlock(&client->buffer_lock);
 
        if (event->type == EV_SYN)
@@ -242,11 +248,21 @@ static int evdev_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
+{
+       unsigned int n_events =
+               max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,
+                   EVDEV_MIN_BUFFER_SIZE);
+
+       return roundup_pow_of_two(n_events);
+}
+
 static int evdev_open(struct inode *inode, struct file *file)
 {
        struct evdev *evdev;
        struct evdev_client *client;
        int i = iminor(inode) - EVDEV_MINOR_BASE;
+       unsigned int bufsize;
        int error;
 
        if (i >= EVDEV_MINORS)
@@ -263,12 +279,17 @@ static int evdev_open(struct inode *inode, struct file *file)
        if (!evdev)
                return -ENODEV;
 
-       client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+       bufsize = evdev_compute_buffer_size(evdev->handle.dev);
+
+       client = kzalloc(sizeof(struct evdev_client) +
+                               bufsize * sizeof(struct input_event),
+                        GFP_KERNEL);
        if (!client) {
                error = -ENOMEM;
                goto err_put_evdev;
        }
 
+       client->bufsize = bufsize;
        spin_lock_init(&client->buffer_lock);
        client->evdev = evdev;
        evdev_attach_client(evdev, client);
@@ -334,7 +355,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,
        have_event = client->head != client->tail;
        if (have_event) {
                *event = client->buffer[client->tail++];
-               client->tail &= EVDEV_BUFFER_SIZE - 1;
+               client->tail &= client->bufsize - 1;
        }
 
        spin_unlock_irq(&client->buffer_lock);
@@ -382,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
 {
        struct evdev_client *client = file->private_data;
        struct evdev *evdev = client->evdev;
+       unsigned int mask;
 
        poll_wait(file, &evdev->wait, wait);
-       return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-               (evdev->exist ? 0 : (POLLHUP | POLLERR));
+
+       mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+       if (client->head != client->tail)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
 }
 
 #ifdef CONFIG_COMPAT
@@ -665,6 +691,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                                                                  sizeof(struct input_absinfo))))
                                        return -EFAULT;
 
+                               /* We can't change number of reserved MT slots */
+                               if (t == ABS_MT_SLOT)
+                                       return -EINVAL;
+
                                /*
                                 * Take event lock to ensure that we are not
                                 * changing device parameters in the middle
@@ -768,7 +798,7 @@ static void evdev_remove_chrdev(struct evdev *evdev)
 static void evdev_mark_dead(struct evdev *evdev)
 {
        mutex_lock(&evdev->mutex);
-       evdev->exist = 0;
+       evdev->exist = false;
        mutex_unlock(&evdev->mutex);
 }
 
@@ -817,7 +847,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
        init_waitqueue_head(&evdev->wait);
 
        dev_set_name(&evdev->dev, "event%d", minor);
-       evdev->exist = 1;
+       evdev->exist = true;
        evdev->minor = minor;
 
        evdev->handle.dev = input_get_device(dev);
index 9c79bd56b51acbf17d90033789801d984bc492b8..e1243b4b32a5bc0a036a2c55a0b6d93a77346e9e 100644 (file)
@@ -33,25 +33,6 @@ MODULE_LICENSE("GPL");
 
 #define INPUT_DEVICES  256
 
-/*
- * EV_ABS events which should not be cached are listed here.
- */
-static unsigned int input_abs_bypass_init_data[] __initdata = {
-       ABS_MT_TOUCH_MAJOR,
-       ABS_MT_TOUCH_MINOR,
-       ABS_MT_WIDTH_MAJOR,
-       ABS_MT_WIDTH_MINOR,
-       ABS_MT_ORIENTATION,
-       ABS_MT_POSITION_X,
-       ABS_MT_POSITION_Y,
-       ABS_MT_TOOL_TYPE,
-       ABS_MT_BLOB_ID,
-       ABS_MT_TRACKING_ID,
-       ABS_MT_PRESSURE,
-       0
-};
-static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
-
 static LIST_HEAD(input_dev_list);
 static LIST_HEAD(input_handler_list);
 
@@ -181,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_DEVICE   2
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
+static int input_handle_abs_event(struct input_dev *dev,
+                                 unsigned int code, int *pval)
+{
+       bool is_mt_event;
+       int *pold;
+
+       if (code == ABS_MT_SLOT) {
+               /*
+                * "Stage" the event; we'll flush it later, when we
+                * get actiual touch data.
+                */
+               if (*pval >= 0 && *pval < dev->mtsize)
+                       dev->slot = *pval;
+
+               return INPUT_IGNORE_EVENT;
+       }
+
+       is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
+
+       if (!is_mt_event) {
+               pold = &dev->abs[code];
+       } else if (dev->mt) {
+               struct input_mt_slot *mtslot = &dev->mt[dev->slot];
+               pold = &mtslot->abs[code - ABS_MT_FIRST];
+       } else {
+               /*
+                * Bypass filtering for multitouch events when
+                * not employing slots.
+                */
+               pold = NULL;
+       }
+
+       if (pold) {
+               *pval = input_defuzz_abs_event(*pval, *pold,
+                                               dev->absfuzz[code]);
+               if (*pold == *pval)
+                       return INPUT_IGNORE_EVENT;
+
+               *pold = *pval;
+       }
+
+       /* Flush pending "slot" event */
+       if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) {
+               dev->abs[ABS_MT_SLOT] = dev->slot;
+               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+       }
+
+       return INPUT_PASS_TO_HANDLERS;
+}
+
 static void input_handle_event(struct input_dev *dev,
                               unsigned int type, unsigned int code, int value)
 {
@@ -196,12 +227,12 @@ static void input_handle_event(struct input_dev *dev,
 
                case SYN_REPORT:
                        if (!dev->sync) {
-                               dev->sync = 1;
+                               dev->sync = true;
                                disposition = INPUT_PASS_TO_HANDLERS;
                        }
                        break;
                case SYN_MT_REPORT:
-                       dev->sync = 0;
+                       dev->sync = false;
                        disposition = INPUT_PASS_TO_HANDLERS;
                        break;
                }
@@ -233,21 +264,9 @@ static void input_handle_event(struct input_dev *dev,
                break;
 
        case EV_ABS:
-               if (is_event_supported(code, dev->absbit, ABS_MAX)) {
-
-                       if (test_bit(code, input_abs_bypass)) {
-                               disposition = INPUT_PASS_TO_HANDLERS;
-                               break;
-                       }
+               if (is_event_supported(code, dev->absbit, ABS_MAX))
+                       disposition = input_handle_abs_event(dev, code, &value);
 
-                       value = input_defuzz_abs_event(value,
-                                       dev->abs[code], dev->absfuzz[code]);
-
-                       if (dev->abs[code] != value) {
-                               dev->abs[code] = value;
-                               disposition = INPUT_PASS_TO_HANDLERS;
-                       }
-               }
                break;
 
        case EV_REL:
@@ -298,7 +317,7 @@ static void input_handle_event(struct input_dev *dev,
        }
 
        if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-               dev->sync = 0;
+               dev->sync = false;
 
        if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
                dev->event(dev, type, code, value);
@@ -527,13 +546,31 @@ void input_close_device(struct input_handle *handle)
 }
 EXPORT_SYMBOL(input_close_device);
 
+/*
+ * Simulate keyup events for all keys that are marked as pressed.
+ * The function must be called with dev->event_lock held.
+ */
+static void input_dev_release_keys(struct input_dev *dev)
+{
+       int code;
+
+       if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
+               for (code = 0; code <= KEY_MAX; code++) {
+                       if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+                           __test_and_clear_bit(code, dev->key)) {
+                               input_pass_event(dev, EV_KEY, code, 0);
+                       }
+               }
+               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+       }
+}
+
 /*
  * Prepare device for unregistering
  */
 static void input_disconnect_device(struct input_dev *dev)
 {
        struct input_handle *handle;
-       int code;
 
        /*
         * Mark device as going away. Note that we take dev->mutex here
@@ -552,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev)
         * generate events even after we done here but they will not
         * reach any handlers.
         */
-       if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
-               for (code = 0; code <= KEY_MAX; code++) {
-                       if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-                           __test_and_clear_bit(code, dev->key)) {
-                               input_pass_event(dev, EV_KEY, code, 0);
-                       }
-               }
-               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-       }
+       input_dev_release_keys(dev);
 
        list_for_each_entry(handle, &dev->h_list, d_node)
                handle->open = 0;
@@ -684,7 +713,7 @@ int input_set_keycode(struct input_dev *dev,
                      unsigned int scancode, unsigned int keycode)
 {
        unsigned long flags;
-       int old_keycode;
+       unsigned int old_keycode;
        int retval;
 
        if (keycode > KEY_MAX)
@@ -1278,6 +1307,7 @@ static void input_dev_release(struct device *device)
        struct input_dev *dev = to_input_dev(device);
 
        input_ff_destroy(dev);
+       input_mt_destroy_slots(dev);
        kfree(dev);
 
        module_put(THIS_MODULE);
@@ -1433,6 +1463,15 @@ static int input_dev_resume(struct device *dev)
 
        mutex_lock(&input_dev->mutex);
        input_dev_reset(input_dev, true);
+
+       /*
+        * Keys that have been pressed at suspend time are unlikely
+        * to be still pressed when we resume.
+        */
+       spin_lock_irq(&input_dev->event_lock);
+       input_dev_release_keys(input_dev);
+       spin_unlock_irq(&input_dev->event_lock);
+
        mutex_unlock(&input_dev->mutex);
 
        return 0;
@@ -1517,6 +1556,45 @@ void input_free_device(struct input_dev *dev)
 }
 EXPORT_SYMBOL(input_free_device);
 
+/**
+ * input_mt_create_slots() - create MT input slots
+ * @dev: input device supporting MT events and finger tracking
+ * @num_slots: number of slots used by the device
+ *
+ * This function allocates all necessary memory for MT slot handling
+ * in the input device, and adds ABS_MT_SLOT to the device capabilities.
+ */
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
+{
+       if (!num_slots)
+               return 0;
+
+       dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
+       if (!dev->mt)
+               return -ENOMEM;
+
+       dev->mtsize = num_slots;
+       input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL(input_mt_create_slots);
+
+/**
+ * input_mt_destroy_slots() - frees the MT slots of the input device
+ * @dev: input device with allocated MT slots
+ *
+ * This function is only needed in error path as the input core will
+ * automatically free the MT slots when the device is destroyed.
+ */
+void input_mt_destroy_slots(struct input_dev *dev)
+{
+       kfree(dev->mt);
+       dev->mt = NULL;
+       dev->mtsize = 0;
+}
+EXPORT_SYMBOL(input_mt_destroy_slots);
+
 /**
  * input_set_capability - mark device as capable of a certain event
  * @dev: device that is capable of emitting or accepting event
@@ -1926,20 +2004,10 @@ static const struct file_operations input_fops = {
        .open = input_open_file,
 };
 
-static void __init input_init_abs_bypass(void)
-{
-       const unsigned int *p;
-
-       for (p = input_abs_bypass_init_data; *p; p++)
-               input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p);
-}
-
 static int __init input_init(void)
 {
        int err;
 
-       input_init_abs_bypass();
-
        err = class_register(&input_class);
        if (err) {
                printk(KERN_ERR "input: unable to register input_dev class\n");
index 34157bb97ed6440695dcafb072ca3f8419cb5d0b..63834585c283593103439b5cf154390a564a6303 100644 (file)
@@ -37,7 +37,6 @@ MODULE_LICENSE("GPL");
 #define JOYDEV_BUFFER_SIZE     64
 
 struct joydev {
-       int exist;
        int open;
        int minor;
        struct input_handle handle;
@@ -46,6 +45,7 @@ struct joydev {
        spinlock_t client_lock; /* protects client_list */
        struct mutex mutex;
        struct device dev;
+       bool exist;
 
        struct js_corr corr[ABS_CNT];
        struct JS_DATA_SAVE_TYPE glue;
@@ -760,7 +760,7 @@ static void joydev_remove_chrdev(struct joydev *joydev)
 static void joydev_mark_dead(struct joydev *joydev)
 {
        mutex_lock(&joydev->mutex);
-       joydev->exist = 0;
+       joydev->exist = false;
        mutex_unlock(&joydev->mutex);
 }
 
@@ -817,10 +817,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
        init_waitqueue_head(&joydev->wait);
 
        dev_set_name(&joydev->dev, "js%d", minor);
-       joydev->exist = 1;
+       joydev->exist = true;
        joydev->minor = minor;
 
-       joydev->exist = 1;
        joydev->handle.dev = input_get_device(dev);
        joydev->handle.name = dev_name(&joydev->dev);
        joydev->handle.handler = handler;
index c1087ce4cef9ddf5e4221d13d35baa65943c8eb3..269a846f3694d3780cd38d6010445ac72bd1e0b2 100644 (file)
@@ -9,6 +9,7 @@
  *               2005 Dominic Cerquetti <binary1230@yahoo.com>
  *               2006 Adam Buchbinder <adam.buchbinder@gmail.com>
  *               2007 Jan Kratochvil <honza@jikos.cz>
+ *               2010 Christoph Fritz <chf.fritz@googlemail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -88,6 +89,9 @@
    but we map them to axes when possible to simplify things */
 #define MAP_DPAD_TO_BUTTONS            (1 << 0)
 #define MAP_TRIGGERS_TO_BUTTONS                (1 << 1)
+#define MAP_STICKS_TO_NULL             (1 << 2)
+#define DANCEPAD_MAP_CONFIG    (MAP_DPAD_TO_BUTTONS |                  \
+                               MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
 
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
@@ -102,6 +106,10 @@ static int triggers_to_buttons;
 module_param(triggers_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
 
+static int sticks_to_null;
+module_param(sticks_to_null, bool, S_IRUGO);
+MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
+
 static const struct xpad_device {
        u16 idVendor;
        u16 idProduct;
@@ -114,7 +122,7 @@ static const struct xpad_device {
        { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
        { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
-       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
        { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
        { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
@@ -151,6 +159,7 @@ static const struct xpad_device {
        { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
        { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -158,7 +167,7 @@ static const struct xpad_device {
 /* buttons shared with xbox and xbox360 */
 static const signed short xpad_common_btn[] = {
        BTN_A, BTN_B, BTN_X, BTN_Y,                     /* "analog" buttons */
-       BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,    /* start/back/sticks */
+       BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR,  /* start/back/sticks */
        -1                                              /* terminating entry */
 };
 
@@ -168,10 +177,10 @@ static const signed short xpad_btn[] = {
        -1                      /* terminating entry */
 };
 
-/* used when dpad is mapped to nuttons */
+/* used when dpad is mapped to buttons */
 static const signed short xpad_btn_pad[] = {
-       BTN_LEFT, BTN_RIGHT,            /* d-pad left, right */
-       BTN_0, BTN_1,                   /* d-pad up, down (XXX names??) */
+       BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2,         /* d-pad left, right */
+       BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4,         /* d-pad up, down */
        -1                              /* terminating entry */
 };
 
@@ -279,17 +288,19 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
 {
        struct input_dev *dev = xpad->dev;
 
-       /* left stick */
-       input_report_abs(dev, ABS_X,
-                        (__s16) le16_to_cpup((__le16 *)(data + 12)));
-       input_report_abs(dev, ABS_Y,
-                        ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
-
-       /* right stick */
-       input_report_abs(dev, ABS_RX,
-                        (__s16) le16_to_cpup((__le16 *)(data + 16)));
-       input_report_abs(dev, ABS_RY,
-                        ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               /* left stick */
+               input_report_abs(dev, ABS_X,
+                                (__s16) le16_to_cpup((__le16 *)(data + 12)));
+               input_report_abs(dev, ABS_Y,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
+
+               /* right stick */
+               input_report_abs(dev, ABS_RX,
+                                (__s16) le16_to_cpup((__le16 *)(data + 16)));
+               input_report_abs(dev, ABS_RY,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+       }
 
        /* triggers left/right */
        if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -302,10 +313,11 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
 
        /* digital pad */
        if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-               input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
-               input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-               input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */
-               input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */
+               /* dpad as buttons (left, right, up, down) */
+               input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+               input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+               input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+               input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
        } else {
                input_report_abs(dev, ABS_HAT0X,
                                 !!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -315,7 +327,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
 
        /* start/back buttons and stick press left/right */
        input_report_key(dev, BTN_START,  data[2] & 0x10);
-       input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+       input_report_key(dev, BTN_SELECT, data[2] & 0x20);
        input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
        input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
 
@@ -349,11 +361,11 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
 
        /* digital pad */
        if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-               /* dpad as buttons (right, left, down, up) */
-               input_report_key(dev, BTN_LEFT, data[2] & 0x04);
-               input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-               input_report_key(dev, BTN_0, data[2] & 0x01);   /* up */
-               input_report_key(dev, BTN_1, data[2] & 0x02);   /* down */
+               /* dpad as buttons (left, right, up, down) */
+               input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+               input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+               input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+               input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
        } else {
                input_report_abs(dev, ABS_HAT0X,
                                 !!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -363,7 +375,7 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
 
        /* start/back buttons */
        input_report_key(dev, BTN_START,  data[2] & 0x10);
-       input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+       input_report_key(dev, BTN_SELECT, data[2] & 0x20);
 
        /* stick press left/right */
        input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
@@ -378,17 +390,19 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
        input_report_key(dev, BTN_TR,   data[3] & 0x02);
        input_report_key(dev, BTN_MODE, data[3] & 0x04);
 
-       /* left stick */
-       input_report_abs(dev, ABS_X,
-                        (__s16) le16_to_cpup((__le16 *)(data + 6)));
-       input_report_abs(dev, ABS_Y,
-                        ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
-
-       /* right stick */
-       input_report_abs(dev, ABS_RX,
-                        (__s16) le16_to_cpup((__le16 *)(data + 10)));
-       input_report_abs(dev, ABS_RY,
-                        ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               /* left stick */
+               input_report_abs(dev, ABS_X,
+                                (__s16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_abs(dev, ABS_Y,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
+
+               /* right stick */
+               input_report_abs(dev, ABS_RX,
+                                (__s16) le16_to_cpup((__le16 *)(data + 10)));
+               input_report_abs(dev, ABS_RY,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+       }
 
        /* triggers left/right */
        if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -814,6 +828,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        xpad->mapping |= MAP_DPAD_TO_BUTTONS;
                if (triggers_to_buttons)
                        xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
+               if (sticks_to_null)
+                       xpad->mapping |= MAP_STICKS_TO_NULL;
        }
 
        xpad->dev = input_dev;
@@ -830,16 +846,20 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        input_dev->open = xpad_open;
        input_dev->close = xpad_close;
 
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               input_dev->evbit[0] |= BIT_MASK(EV_ABS);
+               /* set up axes */
+               for (i = 0; xpad_abs[i] >= 0; i++)
+                       xpad_set_up_abs(input_dev, xpad_abs[i]);
+       }
 
-       /* set up standard buttons and axes */
+       /* set up standard buttons */
        for (i = 0; xpad_common_btn[i] >= 0; i++)
                __set_bit(xpad_common_btn[i], input_dev->keybit);
 
-       for (i = 0; xpad_abs[i] >= 0; i++)
-               xpad_set_up_abs(input_dev, xpad_abs[i]);
-
-       /* Now set up model-specific ones */
+       /* set up model-specific ones */
        if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
                for (i = 0; xpad360_btn[i] >= 0; i++)
                        __set_bit(xpad360_btn[i], input_dev->keybit);
index 1ba25145b333bb79628d2b08c106825ed1c5c5fa..b171f63fe4d716a2bdcd920e73aec80356de0581 100644 (file)
@@ -297,6 +297,18 @@ config KEYBOARD_MAX7359
          To compile this driver as a module, choose M here: the
          module will be called max7359_keypad.
 
+config KEYBOARD_MCS
+       tristate "MELFAS MCS Touchkey"
+       depends on I2C
+       help
+         Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
+         chip in your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mcs_touchkey.
+
 config KEYBOARD_IMX
        tristate "IMX keypad support"
        depends on ARCH_MXC
@@ -342,6 +354,15 @@ config KEYBOARD_PXA930_ROTARY
          To compile this driver as a module, choose M here: the
          module will be called pxa930_rotary.
 
+config KEYBOARD_SAMSUNG
+       tristate "Samsung keypad support"
+       depends on SAMSUNG_DEV_KEYPAD
+       help
+         Say Y here if you want to use the Samsung keypad.
+
+         To compile this driver as a module, choose M here: the
+         module will be called samsung-keypad.
+
 config KEYBOARD_STOWAWAY
        tristate "Stowaway keyboard"
        select SERIO
index 4596d0c6f9228cfeca47a6a08ff019d04e353787..1a66d5f1ca8b0b077438194d046ea125ebcd6d70 100644 (file)
@@ -26,12 +26,14 @@ obj-$(CONFIG_KEYBOARD_LOCOMO)               += locomokbd.o
 obj-$(CONFIG_KEYBOARD_MAPLE)           += maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)          += matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)         += max7359_keypad.o
+obj-$(CONFIG_KEYBOARD_MCS)             += mcs_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-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_QT2160)          += qt2160.o
+obj-$(CONFIG_KEYBOARD_SAMSUNG)         += samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)                += sh_keysc.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
index 744600eff222935b8af076ac8122c07f22a896e9..d6918cb966c0603157265851958fd72e9ce5a7a4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <linux/slab.h>
 
 #include <linux/i2c/adp5588.h>
 
 #define KEYP_MAX_EVENT         10
 
+#define MAXGPIO                        18
+#define ADP_BANK(offs)         ((offs) >> 3)
+#define ADP_BIT(offs)          (1u << ((offs) & 0x7))
+
 /*
  * Early pre 4.0 Silicon required to delay readout by at least 25ms,
  * since the Event Counter Register updated 25ms after the interrupt
@@ -67,6 +72,16 @@ struct adp5588_kpad {
        struct delayed_work work;
        unsigned long delay;
        unsigned short keycode[ADP5588_KEYMAPSIZE];
+       const struct adp5588_gpi_map *gpimap;
+       unsigned short gpimapsize;
+#ifdef CONFIG_GPIOLIB
+       unsigned char gpiomap[MAXGPIO];
+       bool export_gpio;
+       struct gpio_chip gc;
+       struct mutex gpio_lock; /* Protect cached dir, dat_out */
+       u8 dat_out[3];
+       u8 dir[3];
+#endif
 };
 
 static int adp5588_read(struct i2c_client *client, u8 reg)
@@ -84,12 +99,222 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
        return i2c_smbus_write_byte_data(client, reg, val);
 }
 
+#ifdef CONFIG_GPIOLIB
+static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+       struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+       return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+}
+
+static void adp5588_gpio_set_value(struct gpio_chip *chip,
+                                  unsigned off, int val)
+{
+       struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+       mutex_lock(&kpad->gpio_lock);
+
+       if (val)
+               kpad->dat_out[bank] |= bit;
+       else
+               kpad->dat_out[bank] &= ~bit;
+
+       adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+                          kpad->dat_out[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+       struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       int ret;
+
+       mutex_lock(&kpad->gpio_lock);
+
+       kpad->dir[bank] &= ~bit;
+       ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return ret;
+}
+
+static int adp5588_gpio_direction_output(struct gpio_chip *chip,
+                                        unsigned off, int val)
+{
+       struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       int ret;
+
+       mutex_lock(&kpad->gpio_lock);
+
+       kpad->dir[bank] |= bit;
+
+       if (val)
+               kpad->dat_out[bank] |= bit;
+       else
+               kpad->dat_out[bank] &= ~bit;
+
+       ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+                                kpad->dat_out[bank]);
+       ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank,
+                                kpad->dir[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return ret;
+}
+
+static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
+                               const struct adp5588_kpad_platform_data *pdata)
+{
+       bool pin_used[MAXGPIO];
+       int n_unused = 0;
+       int i;
+
+       memset(pin_used, 0, sizeof(pin_used));
+
+       for (i = 0; i < pdata->rows; i++)
+               pin_used[i] = true;
+
+       for (i = 0; i < pdata->cols; i++)
+               pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true;
+
+       for (i = 0; i < kpad->gpimapsize; i++)
+               pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
+
+       for (i = 0; i < MAXGPIO; i++)
+               if (!pin_used[i])
+                       kpad->gpiomap[n_unused++] = i;
+
+       return n_unused;
+}
+
+static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+       struct device *dev = &kpad->client->dev;
+       const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+       const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+       int i, error;
+
+       if (!gpio_data)
+               return 0;
+
+       kpad->gc.ngpio = adp5588_build_gpiomap(kpad, pdata);
+       if (kpad->gc.ngpio == 0) {
+               dev_info(dev, "No unused gpios left to export\n");
+               return 0;
+       }
+
+       kpad->export_gpio = true;
+
+       kpad->gc.direction_input = adp5588_gpio_direction_input;
+       kpad->gc.direction_output = adp5588_gpio_direction_output;
+       kpad->gc.get = adp5588_gpio_get_value;
+       kpad->gc.set = adp5588_gpio_set_value;
+       kpad->gc.can_sleep = 1;
+
+       kpad->gc.base = gpio_data->gpio_start;
+       kpad->gc.label = kpad->client->name;
+       kpad->gc.owner = THIS_MODULE;
+
+       mutex_init(&kpad->gpio_lock);
+
+       error = gpiochip_add(&kpad->gc);
+       if (error) {
+               dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+               kpad->dat_out[i] = adp5588_read(kpad->client,
+                                               GPIO_DAT_OUT1 + i);
+               kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
+       }
+
+       if (gpio_data->setup) {
+               error = gpio_data->setup(kpad->client,
+                                        kpad->gc.base, kpad->gc.ngpio,
+                                        gpio_data->context);
+               if (error)
+                       dev_warn(dev, "setup failed, %d\n", error);
+       }
+
+       return 0;
+}
+
+static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+       struct device *dev = &kpad->client->dev;
+       const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+       const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+       int error;
+
+       if (!kpad->export_gpio)
+               return;
+
+       if (gpio_data->teardown) {
+               error = gpio_data->teardown(kpad->client,
+                                           kpad->gc.base, kpad->gc.ngpio,
+                                           gpio_data->context);
+               if (error)
+                       dev_warn(dev, "teardown failed %d\n", error);
+       }
+
+       error = gpiochip_remove(&kpad->gc);
+       if (error)
+               dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+       return 0;
+}
+
+static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+}
+#endif
+
+static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
+{
+       int i, j;
+
+       for (i = 0; i < ev_cnt; i++) {
+               int key = adp5588_read(kpad->client, Key_EVENTA + i);
+               int key_val = key & KEY_EV_MASK;
+
+               if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) {
+                       for (j = 0; j < kpad->gpimapsize; j++) {
+                               if (key_val == kpad->gpimap[j].pin) {
+                                       input_report_switch(kpad->input,
+                                                       kpad->gpimap[j].sw_evt,
+                                                       key & KEY_EV_PRESSED);
+                                       break;
+                               }
+                       }
+               } else {
+                       input_report_key(kpad->input,
+                                        kpad->keycode[key_val - 1],
+                                        key & KEY_EV_PRESSED);
+               }
+       }
+}
+
 static void adp5588_work(struct work_struct *work)
 {
        struct adp5588_kpad *kpad = container_of(work,
                                                struct adp5588_kpad, work.work);
        struct i2c_client *client = kpad->client;
-       int i, key, status, ev_cnt;
+       int status, ev_cnt;
 
        status = adp5588_read(client, INT_STAT);
 
@@ -99,12 +324,7 @@ static void adp5588_work(struct work_struct *work)
        if (status & KE_INT) {
                ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
                if (ev_cnt) {
-                       for (i = 0; i < ev_cnt; i++) {
-                               key = adp5588_read(client, Key_EVENTA + i);
-                               input_report_key(kpad->input,
-                                       kpad->keycode[(key & KEY_EV_MASK) - 1],
-                                       key & KEY_EV_PRESSED);
-                       }
+                       adp5588_report_events(kpad, ev_cnt);
                        input_sync(kpad->input);
                }
        }
@@ -128,8 +348,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
 
 static int __devinit adp5588_setup(struct i2c_client *client)
 {
-       struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+       const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+       const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
        int i, ret;
+       unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
 
        ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
        ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
@@ -144,6 +366,32 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        for (i = 0; i < KEYP_MAX_EVENT; i++)
                ret |= adp5588_read(client, Key_EVENTA);
 
+       for (i = 0; i < pdata->gpimapsize; i++) {
+               unsigned short pin = pdata->gpimap[i].pin;
+
+               if (pin <= GPI_PIN_ROW_END) {
+                       evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE));
+               } else {
+                       evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF);
+                       evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8);
+               }
+       }
+
+       if (pdata->gpimapsize) {
+               ret |= adp5588_write(client, GPI_EM1, evt_mode1);
+               ret |= adp5588_write(client, GPI_EM2, evt_mode2);
+               ret |= adp5588_write(client, GPI_EM3, evt_mode3);
+       }
+
+       if (gpio_data) {
+               for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+                       int pull_mask = gpio_data->pullup_dis_mask;
+
+                       ret |= adp5588_write(client, GPIO_PULL1 + i,
+                               (pull_mask >> (8 * i)) & 0xFF);
+               }
+       }
+
        ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
                                        OVR_FLOW_INT | K_LCK_INT |
                                        GPI_INT | KE_INT); /* Status is W1C */
@@ -158,11 +406,49 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        return 0;
 }
 
+static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
+{
+       int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
+       int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
+       int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3);
+       int gpi_stat_tmp, pin_loc;
+       int i;
+
+       for (i = 0; i < kpad->gpimapsize; i++) {
+               unsigned short pin = kpad->gpimap[i].pin;
+
+               if (pin <= GPI_PIN_ROW_END) {
+                       gpi_stat_tmp = gpi_stat1;
+                       pin_loc = pin - GPI_PIN_ROW_BASE;
+               } else if ((pin - GPI_PIN_COL_BASE) < 8) {
+                       gpi_stat_tmp = gpi_stat2;
+                       pin_loc = pin - GPI_PIN_COL_BASE;
+               } else {
+                       gpi_stat_tmp = gpi_stat3;
+                       pin_loc = pin - GPI_PIN_COL_BASE - 8;
+               }
+
+               if (gpi_stat_tmp < 0) {
+                       dev_err(&kpad->client->dev,
+                               "Can't read GPIO_DAT_STAT switch %d default to OFF\n",
+                               pin);
+                       gpi_stat_tmp = 0;
+               }
+
+               input_report_switch(kpad->input,
+                                   kpad->gpimap[i].sw_evt,
+                                   !(gpi_stat_tmp & (1 << pin_loc)));
+       }
+
+       input_sync(kpad->input);
+}
+
+
 static int __devinit adp5588_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        struct adp5588_kpad *kpad;
-       struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+       const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
        struct input_dev *input;
        unsigned int revid;
        int ret, i;
@@ -189,6 +475,37 @@ static int __devinit adp5588_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
+       if (!pdata->gpimap && pdata->gpimapsize) {
+               dev_err(&client->dev, "invalid gpimap from pdata\n");
+               return -EINVAL;
+       }
+
+       if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) {
+               dev_err(&client->dev, "invalid gpimapsize\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pdata->gpimapsize; i++) {
+               unsigned short pin = pdata->gpimap[i].pin;
+
+               if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) {
+                       dev_err(&client->dev, "invalid gpi pin data\n");
+                       return -EINVAL;
+               }
+
+               if (pin <= GPI_PIN_ROW_END) {
+                       if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) {
+                               dev_err(&client->dev, "invalid gpi row data\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) {
+                               dev_err(&client->dev, "invalid gpi col data\n");
+                               return -EINVAL;
+                       }
+               }
+       }
+
        if (!client->irq) {
                dev_err(&client->dev, "no IRQ?\n");
                return -EINVAL;
@@ -233,6 +550,9 @@ static int __devinit adp5588_probe(struct i2c_client *client,
        memcpy(kpad->keycode, pdata->keymap,
                pdata->keymapsize * input->keycodesize);
 
+       kpad->gpimap = pdata->gpimap;
+       kpad->gpimapsize = pdata->gpimapsize;
+
        /* setup input device */
        __set_bit(EV_KEY, input->evbit);
 
@@ -243,6 +563,11 @@ static int __devinit adp5588_probe(struct i2c_client *client,
                __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
        __clear_bit(KEY_RESERVED, input->keybit);
 
+       if (kpad->gpimapsize)
+               __set_bit(EV_SW, input->evbit);
+       for (i = 0; i < kpad->gpimapsize; i++)
+               __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
        error = input_register_device(input);
        if (error) {
                dev_err(&client->dev, "unable to register input device\n");
@@ -261,6 +586,13 @@ static int __devinit adp5588_probe(struct i2c_client *client,
        if (error)
                goto err_free_irq;
 
+       if (kpad->gpimapsize)
+               adp5588_report_switch_state(kpad);
+
+       error = adp5588_gpio_add(kpad);
+       if (error)
+               goto err_free_irq;
+
        device_init_wakeup(&client->dev, 1);
        i2c_set_clientdata(client, kpad);
 
@@ -287,6 +619,7 @@ static int __devexit adp5588_remove(struct i2c_client *client)
        free_irq(client->irq, kpad);
        cancel_delayed_work_sync(&kpad->work);
        input_unregister_device(kpad->input);
+       adp5588_gpio_remove(kpad);
        kfree(kpad);
 
        return 0;
index b8213fd13c3f0ab277a51ad167b7ae85ab7fcdff..a9fd147f2ba744150bae9d7f4f763b70700302c2 100644 (file)
@@ -31,6 +31,7 @@ struct gpio_button_data {
        struct input_dev *input;
        struct timer_list timer;
        struct work_struct work;
+       int timer_debounce;     /* in msecs */
        bool disabled;
 };
 
@@ -109,7 +110,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
                 * Disable IRQ and possible debouncing timer.
                 */
                disable_irq(gpio_to_irq(bdata->button->gpio));
-               if (bdata->button->debounce_interval)
+               if (bdata->timer_debounce)
                        del_timer_sync(&bdata->timer);
 
                bdata->disabled = true;
@@ -347,9 +348,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 
        BUG_ON(irq != gpio_to_irq(button->gpio));
 
-       if (button->debounce_interval)
+       if (bdata->timer_debounce)
                mod_timer(&bdata->timer,
-                       jiffies + msecs_to_jiffies(button->debounce_interval));
+                       jiffies + msecs_to_jiffies(bdata->timer_debounce));
        else
                schedule_work(&bdata->work);
 
@@ -383,6 +384,14 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                goto fail3;
        }
 
+       if (button->debounce_interval) {
+               error = gpio_set_debounce(button->gpio,
+                                         button->debounce_interval * 1000);
+               /* use timer if gpiolib doesn't provide debounce */
+               if (error < 0)
+                       bdata->timer_debounce = button->debounce_interval;
+       }
+
        irq = gpio_to_irq(button->gpio);
        if (irq < 0) {
                error = irq;
@@ -498,7 +507,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail2:
        while (--i >= 0) {
                free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
-               if (pdata->buttons[i].debounce_interval)
+               if (ddata->data[i].timer_debounce)
                        del_timer_sync(&ddata->data[i].timer);
                cancel_work_sync(&ddata->data[i].work);
                gpio_free(pdata->buttons[i].gpio);
@@ -526,7 +535,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
        for (i = 0; i < pdata->nbuttons; i++) {
                int irq = gpio_to_irq(pdata->buttons[i].gpio);
                free_irq(irq, &ddata->data[i]);
-               if (pdata->buttons[i].debounce_interval)
+               if (ddata->data[i].timer_debounce)
                        del_timer_sync(&ddata->data[i].timer);
                cancel_work_sync(&ddata->data[i].work);
                gpio_free(pdata->buttons[i].gpio);
index 40b032f0e32cd47a12e33f300810da9a131941c0..f7c2a166576b8cc161c1debb85639c8426906584 100644 (file)
@@ -642,6 +642,7 @@ static int __devinit lm8323_probe(struct i2c_client *client,
        struct lm8323_platform_data *pdata = client->dev.platform_data;
        struct input_dev *idev;
        struct lm8323_chip *lm;
+       int pwm;
        int i, err;
        unsigned long tmo;
        u8 data[2];
@@ -710,8 +711,9 @@ static int __devinit lm8323_probe(struct i2c_client *client,
                goto fail1;
        }
 
-       for (i = 0; i < LM8323_NUM_PWMS; i++) {
-               err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
+       for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) {
+               err = init_pwm(lm, pwm + 1, &client->dev,
+                              pdata->pwm_names[pwm]);
                if (err < 0)
                        goto fail2;
        }
@@ -764,9 +766,9 @@ fail4:
 fail3:
        device_remove_file(&client->dev, &dev_attr_disable_kp);
 fail2:
-       while (--i >= 0)
-               if (lm->pwm[i].enabled)
-                       led_classdev_unregister(&lm->pwm[i].cdev);
+       while (--pwm >= 0)
+               if (lm->pwm[pwm].enabled)
+                       led_classdev_unregister(&lm->pwm[pwm].cdev);
 fail1:
        input_free_device(idev);
        kfree(lm);
index b443e088fd3c0c09e3f103011de69b24070e720f..b02e4268e18fd743b1cb0639399655bb5236a362 100644 (file)
@@ -37,6 +37,7 @@ struct matrix_keypad {
        spinlock_t lock;
        bool scan_pending;
        bool stopped;
+       bool gpio_all_disabled;
 };
 
 /*
@@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
        int i;
 
-       for (i = 0; i < pdata->num_row_gpios; i++)
-               enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+       if (pdata->clustered_irq > 0)
+               enable_irq(pdata->clustered_irq);
+       else {
+               for (i = 0; i < pdata->num_row_gpios; i++)
+                       enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+       }
 }
 
 static void disable_row_irqs(struct matrix_keypad *keypad)
@@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
        int i;
 
-       for (i = 0; i < pdata->num_row_gpios; i++)
-               disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+       if (pdata->clustered_irq > 0)
+               disable_irq_nosync(pdata->clustered_irq);
+       else {
+               for (i = 0; i < pdata->num_row_gpios; i++)
+                       disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+       }
 }
 
 /*
@@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int matrix_keypad_suspend(struct device *dev)
+static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       unsigned int gpio;
        int i;
 
-       matrix_keypad_stop(keypad->input_dev);
+       if (pdata->clustered_irq > 0) {
+               if (enable_irq_wake(pdata->clustered_irq) == 0)
+                       keypad->gpio_all_disabled = true;
+       } else {
 
-       if (device_may_wakeup(&pdev->dev)) {
                for (i = 0; i < pdata->num_row_gpios; i++) {
                        if (!test_bit(i, keypad->disabled_gpios)) {
-                               unsigned int gpio = pdata->row_gpios[i];
+                               gpio = pdata->row_gpios[i];
 
                                if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
                                        __set_bit(i, keypad->disabled_gpios);
                        }
                }
        }
-
-       return 0;
 }
 
-static int matrix_keypad_resume(struct device *dev)
+static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       unsigned int gpio;
        int i;
 
-       if (device_may_wakeup(&pdev->dev)) {
+       if (pdata->clustered_irq > 0) {
+               if (keypad->gpio_all_disabled) {
+                       disable_irq_wake(pdata->clustered_irq);
+                       keypad->gpio_all_disabled = false;
+               }
+       } else {
                for (i = 0; i < pdata->num_row_gpios; i++) {
                        if (test_and_clear_bit(i, keypad->disabled_gpios)) {
-                               unsigned int gpio = pdata->row_gpios[i];
-
+                               gpio = pdata->row_gpios[i];
                                disable_irq_wake(gpio_to_irq(gpio));
                        }
                }
        }
+}
+
+static int matrix_keypad_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+       matrix_keypad_stop(keypad->input_dev);
+
+       if (device_may_wakeup(&pdev->dev))
+               matrix_keypad_enable_wakeup(keypad);
+
+       return 0;
+}
+
+static int matrix_keypad_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev))
+               matrix_keypad_disable_wakeup(keypad);
 
        matrix_keypad_start(keypad->input_dev);
 
@@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
                gpio_direction_input(pdata->row_gpios[i]);
        }
 
-       for (i = 0; i < pdata->num_row_gpios; i++) {
-               err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+       if (pdata->clustered_irq > 0) {
+               err = request_irq(pdata->clustered_irq,
                                matrix_keypad_interrupt,
-                               IRQF_DISABLED |
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               pdata->clustered_irq_flags,
                                "matrix-keypad", keypad);
                if (err) {
                        dev_err(&pdev->dev,
-                               "Unable to acquire interrupt for GPIO line %i\n",
-                               pdata->row_gpios[i]);
-                       goto err_free_irqs;
+                               "Unable to acquire clustered interrupt\n");
+                       goto err_free_rows;
+               }
+       } else {
+               for (i = 0; i < pdata->num_row_gpios; i++) {
+                       err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+                                       matrix_keypad_interrupt,
+                                       IRQF_DISABLED |
+                                       IRQF_TRIGGER_RISING |
+                                       IRQF_TRIGGER_FALLING,
+                                       "matrix-keypad", keypad);
+                       if (err) {
+                               dev_err(&pdev->dev,
+                                       "Unable to acquire interrupt "
+                                       "for GPIO line %i\n",
+                                       pdata->row_gpios[i]);
+                               goto err_free_irqs;
+                       }
                }
        }
 
@@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 0);
 
-       for (i = 0; i < pdata->num_row_gpios; i++) {
-               free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
-               gpio_free(pdata->row_gpios[i]);
+       if (pdata->clustered_irq > 0) {
+               free_irq(pdata->clustered_irq, keypad);
+       } else {
+               for (i = 0; i < pdata->num_row_gpios; i++)
+                       free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
        }
 
+       for (i = 0; i < pdata->num_row_gpios; i++)
+               gpio_free(pdata->row_gpios[i]);
+
        for (i = 0; i < pdata->num_col_gpios; i++)
                gpio_free(pdata->col_gpios[i]);
 
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
new file mode 100644 (file)
index 0000000..63b849d
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ * 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/i2c.h>
+#include <linux/i2c/mcs.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+
+/* MCS5000 Touchkey */
+#define MCS5000_TOUCHKEY_STATUS                0x04
+#define MCS5000_TOUCHKEY_STATUS_PRESS  7
+#define MCS5000_TOUCHKEY_FW            0x0a
+#define MCS5000_TOUCHKEY_BASE_VAL      0x61
+
+/* MCS5080 Touchkey */
+#define MCS5080_TOUCHKEY_STATUS                0x00
+#define MCS5080_TOUCHKEY_STATUS_PRESS  3
+#define MCS5080_TOUCHKEY_FW            0x01
+#define MCS5080_TOUCHKEY_BASE_VAL      0x1
+
+enum mcs_touchkey_type {
+       MCS5000_TOUCHKEY,
+       MCS5080_TOUCHKEY,
+};
+
+struct mcs_touchkey_chip {
+       unsigned int status_reg;
+       unsigned int pressbit;
+       unsigned int press_invert;
+       unsigned int baseval;
+};
+
+struct mcs_touchkey_data {
+       struct i2c_client *client;
+       struct input_dev *input_dev;
+       struct mcs_touchkey_chip chip;
+       unsigned int key_code;
+       unsigned int key_val;
+       unsigned short keycodes[];
+};
+
+static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
+{
+       struct mcs_touchkey_data *data = dev_id;
+       struct mcs_touchkey_chip *chip = &data->chip;
+       struct i2c_client *client = data->client;
+       struct input_dev *input = data->input_dev;
+       unsigned int key_val;
+       unsigned int pressed;
+       int val;
+
+       val = i2c_smbus_read_byte_data(client, chip->status_reg);
+       if (val < 0) {
+               dev_err(&client->dev, "i2c read error [%d]\n", val);
+               goto out;
+       }
+
+       pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
+       if (chip->press_invert)
+               pressed ^= chip->press_invert;
+
+       /* key_val is 0 when released, so we should use key_val of press. */
+       if (pressed) {
+               key_val = val & (0xff >> (8 - chip->pressbit));
+               if (!key_val)
+                       goto out;
+               key_val -= chip->baseval;
+               data->key_code = data->keycodes[key_val];
+               data->key_val = key_val;
+       }
+
+       input_event(input, EV_MSC, MSC_SCAN, data->key_val);
+       input_report_key(input, data->key_code, pressed);
+       input_sync(input);
+
+       dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
+               pressed ? "pressed" : "released");
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static int __devinit mcs_touchkey_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       const struct mcs_platform_data *pdata;
+       struct mcs_touchkey_data *data;
+       struct input_dev *input_dev;
+       unsigned int fw_reg;
+       int fw_ver;
+       int error;
+       int i;
+
+       pdata = client->dev.platform_data;
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       data = kzalloc(sizeof(struct mcs_touchkey_data) +
+                       sizeof(data->keycodes[0]) * (pdata->key_maxval + 1),
+                       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;
+       }
+
+       data->client = client;
+       data->input_dev = input_dev;
+
+       if (id->driver_data == MCS5000_TOUCHKEY) {
+               data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
+               data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
+               data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
+               fw_reg = MCS5000_TOUCHKEY_FW;
+       } else {
+               data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
+               data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
+               data->chip.press_invert = 1;
+               data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
+               fw_reg = MCS5080_TOUCHKEY_FW;
+       }
+
+       fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
+       if (fw_ver < 0) {
+               error = fw_ver;
+               dev_err(&client->dev, "i2c read error[%d]\n", error);
+               goto err_free_mem;
+       }
+       dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
+
+       input_dev->name = "MELPAS MCS Touchkey";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       if (!pdata->no_autorepeat)
+               input_dev->evbit[0] |= BIT_MASK(EV_REP);
+       input_dev->keycode = data->keycodes;
+       input_dev->keycodesize = sizeof(data->keycodes[0]);
+       input_dev->keycodemax = pdata->key_maxval + 1;
+
+       for (i = 0; i < pdata->keymap_size; i++) {
+               unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
+               unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
+
+               data->keycodes[val] = code;
+               __set_bit(code, input_dev->keybit);
+       }
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+       input_set_drvdata(input_dev, data);
+
+       if (pdata->cfg_pin)
+               pdata->cfg_pin();
+
+       error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
+                       IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, data);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+       return error;
+}
+
+static int __devexit mcs_touchkey_remove(struct i2c_client *client)
+{
+       struct mcs_touchkey_data *data = i2c_get_clientdata(client);
+
+       free_irq(client->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id mcs_touchkey_id[] = {
+       { "mcs5000_touchkey", MCS5000_TOUCHKEY },
+       { "mcs5080_touchkey", MCS5080_TOUCHKEY },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
+
+static struct i2c_driver mcs_touchkey_driver = {
+       .driver = {
+               .name   = "mcs_touchkey",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = mcs_touchkey_probe,
+       .remove         = __devexit_p(mcs_touchkey_remove),
+       .id_table       = mcs_touchkey_id,
+};
+
+static int __init mcs_touchkey_init(void)
+{
+       return i2c_add_driver(&mcs_touchkey_driver);
+}
+
+static void __exit mcs_touchkey_exit(void)
+{
+       i2c_del_driver(&mcs_touchkey_driver);
+}
+
+module_init(mcs_touchkey_init);
+module_exit(mcs_touchkey_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
new file mode 100644 (file)
index 0000000..f689f49
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Samsung keypad driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: 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 as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <plat/keypad.h>
+
+#define SAMSUNG_KEYIFCON                       0x00
+#define SAMSUNG_KEYIFSTSCLR                    0x04
+#define SAMSUNG_KEYIFCOL                       0x08
+#define SAMSUNG_KEYIFROW                       0x0c
+#define SAMSUNG_KEYIFFC                                0x10
+
+/* SAMSUNG_KEYIFCON */
+#define SAMSUNG_KEYIFCON_INT_F_EN              (1 << 0)
+#define SAMSUNG_KEYIFCON_INT_R_EN              (1 << 1)
+#define SAMSUNG_KEYIFCON_DF_EN                 (1 << 2)
+#define SAMSUNG_KEYIFCON_FC_EN                 (1 << 3)
+#define SAMSUNG_KEYIFCON_WAKEUPEN              (1 << 4)
+
+/* SAMSUNG_KEYIFSTSCLR */
+#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK         (0xff << 0)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_MASK         (0xff << 8)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET       8
+#define S5PV210_KEYIFSTSCLR_P_INT_MASK         (0x3fff << 0)
+#define S5PV210_KEYIFSTSCLR_R_INT_MASK         (0x3fff << 16)
+#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET       16
+
+/* SAMSUNG_KEYIFCOL */
+#define SAMSUNG_KEYIFCOL_MASK                  (0xff << 0)
+#define S5PV210_KEYIFCOLEN_MASK                        (0xff << 8)
+
+/* SAMSUNG_KEYIFROW */
+#define SAMSUNG_KEYIFROW_MASK                  (0xff << 0)
+#define S5PV210_KEYIFROW_MASK                  (0x3fff << 0)
+
+/* SAMSUNG_KEYIFFC */
+#define SAMSUNG_KEYIFFC_MASK                   (0x3ff << 0)
+
+enum samsung_keypad_type {
+       KEYPAD_TYPE_SAMSUNG,
+       KEYPAD_TYPE_S5PV210,
+};
+
+struct samsung_keypad {
+       struct input_dev *input_dev;
+       struct clk *clk;
+       void __iomem *base;
+       wait_queue_head_t wait;
+       bool stopped;
+       int irq;
+       unsigned int row_shift;
+       unsigned int rows;
+       unsigned int cols;
+       unsigned int row_state[SAMSUNG_MAX_COLS];
+       unsigned short keycodes[];
+};
+
+static int samsung_keypad_is_s5pv210(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       enum samsung_keypad_type type =
+               platform_get_device_id(pdev)->driver_data;
+
+       return type == KEYPAD_TYPE_S5PV210;
+}
+
+static void samsung_keypad_scan(struct samsung_keypad *keypad,
+                               unsigned int *row_state)
+{
+       struct device *dev = keypad->input_dev->dev.parent;
+       unsigned int col;
+       unsigned int val;
+
+       for (col = 0; col < keypad->cols; col++) {
+               if (samsung_keypad_is_s5pv210(dev)) {
+                       val = S5PV210_KEYIFCOLEN_MASK;
+                       val &= ~(1 << col) << 8;
+               } else {
+                       val = SAMSUNG_KEYIFCOL_MASK;
+                       val &= ~(1 << col);
+               }
+
+               writel(val, keypad->base + SAMSUNG_KEYIFCOL);
+               mdelay(1);
+
+               val = readl(keypad->base + SAMSUNG_KEYIFROW);
+               row_state[col] = ~val & ((1 << keypad->rows) - 1);
+       }
+
+       /* KEYIFCOL reg clear */
+       writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static bool samsung_keypad_report(struct samsung_keypad *keypad,
+                                 unsigned int *row_state)
+{
+       struct input_dev *input_dev = keypad->input_dev;
+       unsigned int changed;
+       unsigned int pressed;
+       unsigned int key_down = 0;
+       unsigned int val;
+       unsigned int col, row;
+
+       for (col = 0; col < keypad->cols; col++) {
+               changed = row_state[col] ^ keypad->row_state[col];
+               key_down |= row_state[col];
+               if (!changed)
+                       continue;
+
+               for (row = 0; row < keypad->rows; row++) {
+                       if (!(changed & (1 << row)))
+                               continue;
+
+                       pressed = row_state[col] & (1 << row);
+
+                       dev_dbg(&keypad->input_dev->dev,
+                               "key %s, row: %d, col: %d\n",
+                               pressed ? "pressed" : "released", row, col);
+
+                       val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+
+                       input_event(input_dev, EV_MSC, MSC_SCAN, val);
+                       input_report_key(input_dev,
+                                       keypad->keycodes[val], pressed);
+               }
+               input_sync(keypad->input_dev);
+       }
+
+       memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));
+
+       return key_down;
+}
+
+static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
+{
+       struct samsung_keypad *keypad = dev_id;
+       unsigned int row_state[SAMSUNG_MAX_COLS];
+       unsigned int val;
+       bool key_down;
+
+       do {
+               val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
+               /* Clear interrupt. */
+               writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+               samsung_keypad_scan(keypad, row_state);
+
+               key_down = samsung_keypad_report(keypad, row_state);
+               if (key_down)
+                       wait_event_timeout(keypad->wait, keypad->stopped,
+                                          msecs_to_jiffies(50));
+
+       } while (key_down && !keypad->stopped);
+
+       return IRQ_HANDLED;
+}
+
+static void samsung_keypad_start(struct samsung_keypad *keypad)
+{
+       unsigned int val;
+
+       /* Tell IRQ thread that it may poll the device. */
+       keypad->stopped = false;
+
+       clk_enable(keypad->clk);
+
+       /* Enable interrupt bits. */
+       val = readl(keypad->base + SAMSUNG_KEYIFCON);
+       val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;
+       writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+       /* KEYIFCOL reg clear. */
+       writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static void samsung_keypad_stop(struct samsung_keypad *keypad)
+{
+       unsigned int val;
+
+       /* Signal IRQ thread to stop polling and disable the handler. */
+       keypad->stopped = true;
+       wake_up(&keypad->wait);
+       disable_irq(keypad->irq);
+
+       /* Clear interrupt. */
+       writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+       /* Disable interrupt bits. */
+       val = readl(keypad->base + SAMSUNG_KEYIFCON);
+       val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);
+       writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+       clk_disable(keypad->clk);
+
+       /*
+        * Now that chip should not generate interrupts we can safely
+        * re-enable the handler.
+        */
+       enable_irq(keypad->irq);
+}
+
+static int samsung_keypad_open(struct input_dev *input_dev)
+{
+       struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+       samsung_keypad_start(keypad);
+
+       return 0;
+}
+
+static void samsung_keypad_close(struct input_dev *input_dev)
+{
+       struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+       samsung_keypad_stop(keypad);
+}
+
+static int __devinit samsung_keypad_probe(struct platform_device *pdev)
+{
+       const struct samsung_keypad_platdata *pdata;
+       const struct matrix_keymap_data *keymap_data;
+       struct samsung_keypad *keypad;
+       struct resource *res;
+       struct input_dev *input_dev;
+       unsigned int row_shift;
+       unsigned int keymap_size;
+       int error;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       keymap_data = pdata->keymap_data;
+       if (!keymap_data) {
+               dev_err(&pdev->dev, "no keymap data defined\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)
+               return -EINVAL;
+
+       if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)
+               return -EINVAL;
+
+       /* initialize the gpio */
+       if (pdata->cfg_gpio)
+               pdata->cfg_gpio(pdata->rows, pdata->cols);
+
+       row_shift = get_count_order(pdata->cols);
+       keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
+
+       keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!keypad || !input_dev) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               error = -ENODEV;
+               goto err_free_mem;
+       }
+
+       keypad->base = ioremap(res->start, resource_size(res));
+       if (!keypad->base) {
+               error = -EBUSY;
+               goto err_free_mem;
+       }
+
+       keypad->clk = clk_get(&pdev->dev, "keypad");
+       if (IS_ERR(keypad->clk)) {
+               dev_err(&pdev->dev, "failed to get keypad clk\n");
+               error = PTR_ERR(keypad->clk);
+               goto err_unmap_base;
+       }
+
+       keypad->input_dev = input_dev;
+       keypad->row_shift = row_shift;
+       keypad->rows = pdata->rows;
+       keypad->cols = pdata->cols;
+       init_waitqueue_head(&keypad->wait);
+
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->dev.parent = &pdev->dev;
+       input_set_drvdata(input_dev, keypad);
+
+       input_dev->open = samsung_keypad_open;
+       input_dev->close = samsung_keypad_close;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       if (!pdata->no_autorepeat)
+               input_dev->evbit[0] |= BIT_MASK(EV_REP);
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+       input_dev->keycode = keypad->keycodes;
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = pdata->rows << row_shift;
+
+       matrix_keypad_build_keymap(keymap_data, row_shift,
+                       input_dev->keycode, input_dev->keybit);
+
+       keypad->irq = platform_get_irq(pdev, 0);
+       if (keypad->irq < 0) {
+               error = keypad->irq;
+               goto err_put_clk;
+       }
+
+       error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
+                       IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register keypad interrupt\n");
+               goto err_put_clk;
+       }
+
+       error = input_register_device(keypad->input_dev);
+       if (error)
+               goto err_free_irq;
+
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+       platform_set_drvdata(pdev, keypad);
+       return 0;
+
+err_free_irq:
+       free_irq(keypad->irq, keypad);
+err_put_clk:
+       clk_put(keypad->clk);
+err_unmap_base:
+       iounmap(keypad->base);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(keypad);
+
+       return error;
+}
+
+static int __devexit samsung_keypad_remove(struct platform_device *pdev)
+{
+       struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+
+       device_init_wakeup(&pdev->dev, 0);
+       platform_set_drvdata(pdev, NULL);
+
+       input_unregister_device(keypad->input_dev);
+
+       /*
+        * It is safe to free IRQ after unregistering device because
+        * samsung_keypad_close will shut off interrupts.
+        */
+       free_irq(keypad->irq, keypad);
+
+       clk_put(keypad->clk);
+
+       iounmap(keypad->base);
+       kfree(keypad);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
+                                        bool enable)
+{
+       struct device *dev = keypad->input_dev->dev.parent;
+       unsigned int val;
+
+       clk_enable(keypad->clk);
+
+       val = readl(keypad->base + SAMSUNG_KEYIFCON);
+       if (enable) {
+               val |= SAMSUNG_KEYIFCON_WAKEUPEN;
+               if (device_may_wakeup(dev))
+                       enable_irq_wake(keypad->irq);
+       } else {
+               val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
+               if (device_may_wakeup(dev))
+                       disable_irq_wake(keypad->irq);
+       }
+       writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+       clk_disable(keypad->clk);
+}
+
+static int samsung_keypad_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+       struct input_dev *input_dev = keypad->input_dev;
+
+       mutex_lock(&input_dev->mutex);
+
+       if (input_dev->users)
+               samsung_keypad_stop(keypad);
+
+       samsung_keypad_toggle_wakeup(keypad, true);
+
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static int samsung_keypad_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+       struct input_dev *input_dev = keypad->input_dev;
+
+       mutex_lock(&input_dev->mutex);
+
+       samsung_keypad_toggle_wakeup(keypad, false);
+
+       if (input_dev->users)
+               samsung_keypad_start(keypad);
+
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static const struct dev_pm_ops samsung_keypad_pm_ops = {
+       .suspend        = samsung_keypad_suspend,
+       .resume         = samsung_keypad_resume,
+};
+#endif
+
+static struct platform_device_id samsung_keypad_driver_ids[] = {
+       {
+               .name           = "samsung-keypad",
+               .driver_data    = KEYPAD_TYPE_SAMSUNG,
+       }, {
+               .name           = "s5pv210-keypad",
+               .driver_data    = KEYPAD_TYPE_S5PV210,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
+
+static struct platform_driver samsung_keypad_driver = {
+       .probe          = samsung_keypad_probe,
+       .remove         = __devexit_p(samsung_keypad_remove),
+       .driver         = {
+               .name   = "samsung-keypad",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &samsung_keypad_pm_ops,
+#endif
+       },
+       .id_table       = samsung_keypad_driver_ids,
+};
+
+static int __init samsung_keypad_init(void)
+{
+       return platform_driver_register(&samsung_keypad_driver);
+}
+module_init(samsung_keypad_init);
+
+static void __exit samsung_keypad_exit(void)
+{
+       platform_driver_unregister(&samsung_keypad_driver);
+}
+module_exit(samsung_keypad_exit);
+
+MODULE_DESCRIPTION("Samsung keypad driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-keypad");
index c44b9eafc556e48c114780e0dc7ed6af1e144cda..b49e233797235e8169ee999f4b2305fa301e327d 100644 (file)
@@ -327,6 +327,17 @@ config INPUT_PCF8574
          To compile this driver as a module, choose M here: the
          module will be called pcf8574_keypad.
 
+config INPUT_PWM_BEEPER
+       tristate "PWM beeper support"
+       depends on HAVE_PWM
+       help
+         Say Y here to get support for PWM based beeper devices.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the module will be
+         called pwm-beeper.
+
 config INPUT_GPIO_ROTARY_ENCODER
        tristate "Rotary encoders connected to GPIO pins"
        depends on GPIOLIB && GENERIC_GPIO
@@ -390,4 +401,41 @@ config INPUT_PCAP
          To compile this driver as a module, choose M here: the
          module will be called pcap_keys.
 
+config INPUT_ADXL34X
+       tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
+       default n
+       help
+         Say Y here if you have a Accelerometer interface using the
+         ADXL345/6 controller, and your board-specific initialization
+         code includes that in its table of devices.
+
+         This driver can use either I2C or SPI communication to the
+         ADXL345/6 controller.  Select the appropriate method for
+         your system.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called adxl34x.
+
+config INPUT_ADXL34X_I2C
+       tristate "support I2C bus connection"
+       depends on INPUT_ADXL34X && I2C
+       default y
+       help
+         Say Y here if you have ADXL345/6 hooked to an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adxl34x-i2c.
+
+config INPUT_ADXL34X_SPI
+       tristate "support SPI bus connection"
+       depends on INPUT_ADXL34X && SPI
+       default y
+       help
+         Say Y here if you have ADXL345/6 hooked to a SPI bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adxl34x-spi.
+
 endif
index 71fe57d8023ff834284afc91ad57fcd08c97606e..19ccca78fa766d2ea2bb24f78201a6b6d9ec770c 100644 (file)
@@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY)      += 88pm860x_onkey.o
 obj-$(CONFIG_INPUT_AD714X)             += ad714x.o
 obj-$(CONFIG_INPUT_AD714X_I2C)         += ad714x-i2c.o
 obj-$(CONFIG_INPUT_AD714X_SPI)         += ad714x-spi.o
+obj-$(CONFIG_INPUT_ADXL34X)            += adxl34x.o
+obj-$(CONFIG_INPUT_ADXL34X_I2C)                += adxl34x-i2c.o
+obj-$(CONFIG_INPUT_ADXL34X_SPI)                += adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)             += apanel.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)         += ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
@@ -26,6 +29,7 @@ obj-$(CONFIG_INPUT_PCF50633_PMU)      += pcf50633-input.o
 obj-$(CONFIG_INPUT_PCF8574)            += pcf8574_keypad.o
 obj-$(CONFIG_INPUT_PCSPKR)             += pcspkr.o
 obj-$(CONFIG_INPUT_POWERMATE)          += powermate.o
+obj-$(CONFIG_INPUT_PWM_BEEPER)         += pwm-beeper.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)       += rb532_button.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)        += rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)           += sgi_btns.o
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
new file mode 100644 (file)
index 0000000..0779724
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>       /* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adxl34x_smbus_write(struct device *dev,
+                              unsigned char reg, unsigned char val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adxl34x_smbus_read_block(struct device *dev,
+                                   unsigned char reg, int count,
+                                   void *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
+}
+
+static int adxl34x_i2c_read_block(struct device *dev,
+                                 unsigned char reg, int count,
+                                 void *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret;
+
+       ret = i2c_master_send(client, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_master_recv(client, buf, count);
+       if (ret < 0)
+               return ret;
+
+       if (ret != count)
+               return -EIO;
+
+       return 0;
+}
+
+static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
+       .bustype        = BUS_I2C,
+       .write          = adxl34x_smbus_write,
+       .read           = adxl34x_smbus_read,
+       .read_block     = adxl34x_smbus_read_block,
+};
+
+static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
+       .bustype        = BUS_I2C,
+       .write          = adxl34x_smbus_write,
+       .read           = adxl34x_smbus_read,
+       .read_block     = adxl34x_i2c_read_block,
+};
+
+static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
+                                      const struct i2c_device_id *id)
+{
+       struct adxl34x *ac;
+       int error;
+
+       error = i2c_check_functionality(client->adapter,
+                       I2C_FUNC_SMBUS_BYTE_DATA);
+       if (!error) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       ac = adxl34x_probe(&client->dev, client->irq, false,
+                          i2c_check_functionality(client->adapter,
+                                                  I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
+                               &adxl34x_smbus_bops : &adxl34x_i2c_bops);
+       if (IS_ERR(ac))
+               return PTR_ERR(ac);
+
+       i2c_set_clientdata(client, ac);
+
+       return 0;
+}
+
+static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
+{
+       struct adxl34x *ac = i2c_get_clientdata(client);
+
+       return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+       struct adxl34x *ac = i2c_get_clientdata(client);
+
+       adxl34x_suspend(ac);
+
+       return 0;
+}
+
+static int adxl34x_i2c_resume(struct i2c_client *client)
+{
+       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 const struct i2c_device_id adxl34x_id[] = {
+       { "adxl34x", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, adxl34x_id);
+
+static struct i2c_driver adxl34x_driver = {
+       .driver = {
+               .name = "adxl34x",
+               .owner = THIS_MODULE,
+       },
+       .probe    = adxl34x_i2c_probe,
+       .remove   = __devexit_p(adxl34x_i2c_remove),
+       .suspend  = adxl34x_i2c_suspend,
+       .resume   = adxl34x_i2c_resume,
+       .id_table = adxl34x_id,
+};
+
+static int __init adxl34x_i2c_init(void)
+{
+       return i2c_add_driver(&adxl34x_driver);
+}
+module_init(adxl34x_i2c_init);
+
+static void __exit adxl34x_i2c_exit(void)
+{
+       i2c_del_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
new file mode 100644 (file)
index 0000000..782de9e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>       /* BUS_SPI */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+#define MAX_SPI_FREQ_HZ                5000000
+#define MAX_FREQ_NO_FIFODELAY  1500000
+#define ADXL34X_CMD_MULTB      (1 << 6)
+#define ADXL34X_CMD_READ       (1 << 7)
+#define ADXL34X_WRITECMD(reg)  (reg & 0x3F)
+#define ADXL34X_READCMD(reg)   (ADXL34X_CMD_READ | (reg & 0x3F))
+#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
+                                       | (reg & 0x3F))
+
+static int adxl34x_spi_read(struct device *dev, unsigned char reg)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char cmd;
+
+       cmd = ADXL34X_READCMD(reg);
+
+       return spi_w8r8(spi, cmd);
+}
+
+static int adxl34x_spi_write(struct device *dev,
+                            unsigned char reg, unsigned char val)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       buf[0] = ADXL34X_WRITECMD(reg);
+       buf[1] = val;
+
+       return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adxl34x_spi_read_block(struct device *dev,
+                                 unsigned char reg, int count,
+                                 void *buf)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       ssize_t status;
+
+       reg = ADXL34X_READMB_CMD(reg);
+       status = spi_write_then_read(spi, &reg, 1, buf, count);
+
+       return (status < 0) ? status : 0;
+}
+
+static const struct adxl34x_bus_ops adx134x_spi_bops = {
+       .bustype        = BUS_SPI,
+       .write          = adxl34x_spi_write,
+       .read           = adxl34x_spi_read,
+       .read_block     = adxl34x_spi_read_block,
+};
+
+static int __devinit adxl34x_spi_probe(struct spi_device *spi)
+{
+       struct adxl34x *ac;
+
+       /* don't exceed max specified SPI CLK frequency */
+       if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+               dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
+               return -EINVAL;
+       }
+
+       ac = adxl34x_probe(&spi->dev, spi->irq,
+                          spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
+                          &adx134x_spi_bops);
+
+       if (IS_ERR(ac))
+               return PTR_ERR(ac);
+
+       spi_set_drvdata(spi, ac);
+
+       return 0;
+}
+
+static int __devexit adxl34x_spi_remove(struct spi_device *spi)
+{
+       struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+       return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+       struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+       adxl34x_suspend(ac);
+
+       return 0;
+}
+
+static int adxl34x_spi_resume(struct spi_device *spi)
+{
+       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 struct spi_driver adxl34x_driver = {
+       .driver = {
+               .name = "adxl34x",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .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)
+{
+       return spi_register_driver(&adxl34x_driver);
+}
+module_init(adxl34x_spi_init);
+
+static void __exit adxl34x_spi_exit(void)
+{
+       spi_unregister_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
new file mode 100644 (file)
index 0000000..e2ca017
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/input/adxl34x.h>
+
+#include "adxl34x.h"
+
+/* ADXL345/6 Register Map */
+#define DEVID          0x00    /* R   Device ID */
+#define THRESH_TAP     0x1D    /* R/W Tap threshold */
+#define OFSX           0x1E    /* R/W X-axis offset */
+#define OFSY           0x1F    /* R/W Y-axis offset */
+#define OFSZ           0x20    /* R/W Z-axis offset */
+#define DUR            0x21    /* R/W Tap duration */
+#define LATENT         0x22    /* R/W Tap latency */
+#define WINDOW         0x23    /* R/W Tap window */
+#define THRESH_ACT     0x24    /* R/W Activity threshold */
+#define THRESH_INACT   0x25    /* R/W Inactivity threshold */
+#define TIME_INACT     0x26    /* R/W Inactivity time */
+#define ACT_INACT_CTL  0x27    /* R/W Axis enable control for activity and */
+                               /* inactivity detection */
+#define THRESH_FF      0x28    /* R/W Free-fall threshold */
+#define TIME_FF                0x29    /* R/W Free-fall time */
+#define TAP_AXES       0x2A    /* R/W Axis control for tap/double tap */
+#define ACT_TAP_STATUS 0x2B    /* R   Source of tap/double tap */
+#define BW_RATE                0x2C    /* R/W Data rate and power mode control */
+#define POWER_CTL      0x2D    /* R/W Power saving features control */
+#define INT_ENABLE     0x2E    /* R/W Interrupt enable control */
+#define INT_MAP                0x2F    /* R/W Interrupt mapping control */
+#define INT_SOURCE     0x30    /* R   Source of interrupts */
+#define DATA_FORMAT    0x31    /* R/W Data format control */
+#define DATAX0         0x32    /* R   X-Axis Data 0 */
+#define DATAX1         0x33    /* R   X-Axis Data 1 */
+#define DATAY0         0x34    /* R   Y-Axis Data 0 */
+#define DATAY1         0x35    /* R   Y-Axis Data 1 */
+#define DATAZ0         0x36    /* R   Z-Axis Data 0 */
+#define DATAZ1         0x37    /* R   Z-Axis Data 1 */
+#define FIFO_CTL       0x38    /* R/W FIFO control */
+#define FIFO_STATUS    0x39    /* R   FIFO status */
+#define TAP_SIGN       0x3A    /* R   Sign and source for tap/double tap */
+/* Orientation ADXL346 only */
+#define ORIENT_CONF    0x3B    /* R/W Orientation configuration */
+#define ORIENT         0x3C    /* R   Orientation status */
+
+/* DEVIDs */
+#define ID_ADXL345     0xE5
+#define ID_ADXL346     0xE6
+
+/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
+#define DATA_READY     (1 << 7)
+#define SINGLE_TAP     (1 << 6)
+#define DOUBLE_TAP     (1 << 5)
+#define ACTIVITY       (1 << 4)
+#define INACTIVITY     (1 << 3)
+#define FREE_FALL      (1 << 2)
+#define WATERMARK      (1 << 1)
+#define OVERRUN                (1 << 0)
+
+/* ACT_INACT_CONTROL Bits */
+#define ACT_ACDC       (1 << 7)
+#define ACT_X_EN       (1 << 6)
+#define ACT_Y_EN       (1 << 5)
+#define ACT_Z_EN       (1 << 4)
+#define INACT_ACDC     (1 << 3)
+#define INACT_X_EN     (1 << 2)
+#define INACT_Y_EN     (1 << 1)
+#define INACT_Z_EN     (1 << 0)
+
+/* TAP_AXES Bits */
+#define SUPPRESS       (1 << 3)
+#define TAP_X_EN       (1 << 2)
+#define TAP_Y_EN       (1 << 1)
+#define TAP_Z_EN       (1 << 0)
+
+/* ACT_TAP_STATUS Bits */
+#define ACT_X_SRC      (1 << 6)
+#define ACT_Y_SRC      (1 << 5)
+#define ACT_Z_SRC      (1 << 4)
+#define ASLEEP         (1 << 3)
+#define TAP_X_SRC      (1 << 2)
+#define TAP_Y_SRC      (1 << 1)
+#define TAP_Z_SRC      (1 << 0)
+
+/* BW_RATE Bits */
+#define LOW_POWER      (1 << 4)
+#define RATE(x)                ((x) & 0xF)
+
+/* POWER_CTL Bits */
+#define PCTL_LINK      (1 << 5)
+#define PCTL_AUTO_SLEEP (1 << 4)
+#define PCTL_MEASURE   (1 << 3)
+#define PCTL_SLEEP     (1 << 2)
+#define PCTL_WAKEUP(x) ((x) & 0x3)
+
+/* DATA_FORMAT Bits */
+#define SELF_TEST      (1 << 7)
+#define SPI            (1 << 6)
+#define INT_INVERT     (1 << 5)
+#define FULL_RES       (1 << 3)
+#define JUSTIFY                (1 << 2)
+#define RANGE(x)       ((x) & 0x3)
+#define RANGE_PM_2g    0
+#define RANGE_PM_4g    1
+#define RANGE_PM_8g    2
+#define RANGE_PM_16g   3
+
+/*
+ * Maximum value our axis may get in full res mode for the input device
+ * (signed 13 bits)
+ */
+#define ADXL_FULLRES_MAX_VAL 4096
+
+/*
+ * Maximum value our axis may get in fixed res mode for the input device
+ * (signed 10 bits)
+ */
+#define ADXL_FIXEDRES_MAX_VAL 512
+
+/* FIFO_CTL Bits */
+#define FIFO_MODE(x)   (((x) & 0x3) << 6)
+#define FIFO_BYPASS    0
+#define FIFO_FIFO      1
+#define FIFO_STREAM    2
+#define FIFO_TRIGGER   3
+#define TRIGGER                (1 << 5)
+#define SAMPLES(x)     ((x) & 0x1F)
+
+/* FIFO_STATUS Bits */
+#define FIFO_TRIG      (1 << 7)
+#define ENTRIES(x)     ((x) & 0x3F)
+
+/* TAP_SIGN Bits ADXL346 only */
+#define XSIGN          (1 << 6)
+#define YSIGN          (1 << 5)
+#define ZSIGN          (1 << 4)
+#define XTAP           (1 << 3)
+#define YTAP           (1 << 2)
+#define ZTAP           (1 << 1)
+
+/* ORIENT_CONF ADXL346 only */
+#define ORIENT_DEADZONE(x)     (((x) & 0x7) << 4)
+#define ORIENT_DIVISOR(x)      ((x) & 0x7)
+
+/* ORIENT ADXL346 only */
+#define ADXL346_2D_VALID               (1 << 6)
+#define ADXL346_2D_ORIENT(x)           (((x) & 0x3) >> 4)
+#define ADXL346_3D_VALID               (1 << 3)
+#define ADXL346_3D_ORIENT(x)           ((x) & 0x7)
+#define ADXL346_2D_PORTRAIT_POS                0       /* +X */
+#define ADXL346_2D_PORTRAIT_NEG                1       /* -X */
+#define ADXL346_2D_LANDSCAPE_POS       2       /* +Y */
+#define ADXL346_2D_LANDSCAPE_NEG       3       /* -Y */
+
+#define ADXL346_3D_FRONT               3       /* +X */
+#define ADXL346_3D_BACK                        4       /* -X */
+#define ADXL346_3D_RIGHT               2       /* +Y */
+#define ADXL346_3D_LEFT                        5       /* -Y */
+#define ADXL346_3D_TOP                 1       /* +Z */
+#define ADXL346_3D_BOTTOM              6       /* -Z */
+
+#undef ADXL_DEBUG
+
+#define ADXL_X_AXIS                    0
+#define ADXL_Y_AXIS                    1
+#define ADXL_Z_AXIS                    2
+
+#define AC_READ(ac, reg)       ((ac)->bops->read((ac)->dev, reg))
+#define AC_WRITE(ac, reg, val) ((ac)->bops->write((ac)->dev, reg, val))
+
+struct axis_triple {
+       int x;
+       int y;
+       int z;
+};
+
+struct adxl34x {
+       struct device *dev;
+       struct input_dev *input;
+       struct mutex mutex;     /* reentrant protection for struct */
+       struct adxl34x_platform_data pdata;
+       struct axis_triple swcal;
+       struct axis_triple hwcal;
+       struct axis_triple saved;
+       char phys[32];
+       unsigned orient2d_saved;
+       unsigned orient3d_saved;
+       bool disabled;  /* P: mutex */
+       bool opened;    /* P: mutex */
+       bool suspended; /* P: mutex */
+       bool fifo_delay;
+       int irq;
+       unsigned model;
+       unsigned int_mask;
+
+       const struct adxl34x_bus_ops *bops;
+};
+
+static const struct adxl34x_platform_data adxl34x_default_init = {
+       .tap_threshold = 35,
+       .tap_duration = 3,
+       .tap_latency = 20,
+       .tap_window = 20,
+       .tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+       .act_axis_control = 0xFF,
+       .activity_threshold = 6,
+       .inactivity_threshold = 4,
+       .inactivity_time = 3,
+       .free_fall_threshold = 8,
+       .free_fall_time = 0x20,
+       .data_rate = 8,
+       .data_range = ADXL_FULL_RES,
+
+       .ev_type = EV_ABS,
+       .ev_code_x = ABS_X,     /* EV_REL */
+       .ev_code_y = ABS_Y,     /* EV_REL */
+       .ev_code_z = ABS_Z,     /* EV_REL */
+
+       .ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
+       .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+       .fifo_mode = FIFO_STREAM,
+       .watermark = 0,
+};
+
+static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
+{
+       short buf[3];
+
+       ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
+
+       mutex_lock(&ac->mutex);
+       ac->saved.x = (s16) le16_to_cpu(buf[0]);
+       axis->x = ac->saved.x;
+
+       ac->saved.y = (s16) le16_to_cpu(buf[1]);
+       axis->y = ac->saved.y;
+
+       ac->saved.z = (s16) le16_to_cpu(buf[2]);
+       axis->z = ac->saved.z;
+       mutex_unlock(&ac->mutex);
+}
+
+static void adxl34x_service_ev_fifo(struct adxl34x *ac)
+{
+       struct adxl34x_platform_data *pdata = &ac->pdata;
+       struct axis_triple axis;
+
+       adxl34x_get_triple(ac, &axis);
+
+       input_event(ac->input, pdata->ev_type, pdata->ev_code_x,
+                   axis.x - ac->swcal.x);
+       input_event(ac->input, pdata->ev_type, pdata->ev_code_y,
+                   axis.y - ac->swcal.y);
+       input_event(ac->input, pdata->ev_type, pdata->ev_code_z,
+                   axis.z - ac->swcal.z);
+}
+
+static void adxl34x_report_key_single(struct input_dev *input, int key)
+{
+       input_report_key(input, key, true);
+       input_sync(input);
+       input_report_key(input, key, false);
+}
+
+static void adxl34x_send_key_events(struct adxl34x *ac,
+               struct adxl34x_platform_data *pdata, int status, int press)
+{
+       int i;
+
+       for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) {
+               if (status & (1 << (ADXL_Z_AXIS - i)))
+                       input_report_key(ac->input,
+                                        pdata->ev_code_tap[i], press);
+       }
+}
+
+static void adxl34x_do_tap(struct adxl34x *ac,
+               struct adxl34x_platform_data *pdata, int status)
+{
+       adxl34x_send_key_events(ac, pdata, status, true);
+       input_sync(ac->input);
+       adxl34x_send_key_events(ac, pdata, status, false);
+}
+
+static irqreturn_t adxl34x_irq(int irq, void *handle)
+{
+       struct adxl34x *ac = handle;
+       struct adxl34x_platform_data *pdata = &ac->pdata;
+       int int_stat, tap_stat, samples, orient, orient_code;
+
+       /*
+        * ACT_TAP_STATUS should be read before clearing the interrupt
+        * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
+        */
+
+       if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+               tap_stat = AC_READ(ac, ACT_TAP_STATUS);
+       else
+               tap_stat = 0;
+
+       int_stat = AC_READ(ac, INT_SOURCE);
+
+       if (int_stat & FREE_FALL)
+               adxl34x_report_key_single(ac->input, pdata->ev_code_ff);
+
+       if (int_stat & OVERRUN)
+               dev_dbg(ac->dev, "OVERRUN\n");
+
+       if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) {
+               adxl34x_do_tap(ac, pdata, tap_stat);
+
+               if (int_stat & DOUBLE_TAP)
+                       adxl34x_do_tap(ac, pdata, tap_stat);
+       }
+
+       if (pdata->ev_code_act_inactivity) {
+               if (int_stat & ACTIVITY)
+                       input_report_key(ac->input,
+                                        pdata->ev_code_act_inactivity, 1);
+               if (int_stat & INACTIVITY)
+                       input_report_key(ac->input,
+                                        pdata->ev_code_act_inactivity, 0);
+       }
+
+       /*
+        * ORIENTATION SENSING ADXL346 only
+        */
+       if (pdata->orientation_enable) {
+               orient = AC_READ(ac, ORIENT);
+               if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
+                   (orient & ADXL346_2D_VALID)) {
+
+                       orient_code = ADXL346_2D_ORIENT(orient);
+                       /* Report orientation only when it changes */
+                       if (ac->orient2d_saved != orient_code) {
+                               ac->orient2d_saved = orient_code;
+                               adxl34x_report_key_single(ac->input,
+                                       pdata->ev_codes_orient_2d[orient_code]);
+                       }
+               }
+
+               if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
+                   (orient & ADXL346_3D_VALID)) {
+
+                       orient_code = ADXL346_3D_ORIENT(orient) - 1;
+                       /* Report orientation only when it changes */
+                       if (ac->orient3d_saved != orient_code) {
+                               ac->orient3d_saved = orient_code;
+                               adxl34x_report_key_single(ac->input,
+                                       pdata->ev_codes_orient_3d[orient_code]);
+                       }
+               }
+       }
+
+       if (int_stat & (DATA_READY | WATERMARK)) {
+
+               if (pdata->fifo_mode)
+                       samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1;
+               else
+                       samples = 1;
+
+               for (; samples > 0; samples--) {
+                       adxl34x_service_ev_fifo(ac);
+                       /*
+                        * To ensure that the FIFO has
+                        * completely popped, there must be at least 5 us between
+                        * the end of reading the data registers, signified by the
+                        * transition to register 0x38 from 0x37 or the CS pin
+                        * going high, and the start of new reads of the FIFO or
+                        * reading the FIFO_STATUS register. For SPI operation at
+                        * 1.5 MHz or lower, the register addressing portion of the
+                        * transmission is sufficient delay to ensure the FIFO has
+                        * completely popped. It is necessary for SPI operation
+                        * greater than 1.5 MHz to de-assert the CS pin to ensure a
+                        * total of 5 us, which is at most 3.4 us at 5 MHz
+                        * operation.
+                        */
+                       if (ac->fifo_delay && (samples > 1))
+                               udelay(3);
+               }
+       }
+
+       input_sync(ac->input);
+
+       return IRQ_HANDLED;
+}
+
+static void __adxl34x_disable(struct adxl34x *ac)
+{
+       /*
+        * A '0' places the ADXL34x into standby mode
+        * with minimum power consumption.
+        */
+       AC_WRITE(ac, POWER_CTL, 0);
+}
+
+static void __adxl34x_enable(struct adxl34x *ac)
+{
+       AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+}
+
+void adxl34x_suspend(struct adxl34x *ac)
+{
+       mutex_lock(&ac->mutex);
+
+       if (!ac->suspended && !ac->disabled && ac->opened)
+               __adxl34x_disable(ac);
+
+       ac->suspended = true;
+
+       mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_suspend);
+
+void adxl34x_resume(struct adxl34x *ac)
+{
+       mutex_lock(&ac->mutex);
+
+       if (ac->suspended && !ac->disabled && ac->opened)
+               __adxl34x_enable(ac);
+
+       ac->suspended = false;
+
+       mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_resume);
+
+static ssize_t adxl34x_disable_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", ac->disabled);
+}
+
+static ssize_t adxl34x_disable_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+       unsigned long val;
+       int error;
+
+       error = strict_strtoul(buf, 10, &val);
+       if (error)
+               return error;
+
+       mutex_lock(&ac->mutex);
+
+       if (!ac->suspended && ac->opened) {
+               if (val) {
+                       if (!ac->disabled)
+                               __adxl34x_disable(ac);
+               } else {
+                       if (ac->disabled)
+                               __adxl34x_enable(ac);
+               }
+       }
+
+       ac->disabled = !!val;
+
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store);
+
+static ssize_t adxl34x_calibrate_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+       ssize_t count;
+
+       mutex_lock(&ac->mutex);
+       count = sprintf(buf, "%d,%d,%d\n",
+                       ac->hwcal.x * 4 + ac->swcal.x,
+                       ac->hwcal.y * 4 + ac->swcal.y,
+                       ac->hwcal.z * 4 + ac->swcal.z);
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static ssize_t adxl34x_calibrate_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+
+       /*
+        * Hardware offset calibration has a resolution of 15.6 mg/LSB.
+        * We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
+        */
+
+       mutex_lock(&ac->mutex);
+       ac->hwcal.x -= (ac->saved.x / 4);
+       ac->swcal.x = ac->saved.x % 4;
+
+       ac->hwcal.y -= (ac->saved.y / 4);
+       ac->swcal.y = ac->saved.y % 4;
+
+       ac->hwcal.z -= (ac->saved.z / 4);
+       ac->swcal.z = ac->saved.z % 4;
+
+       AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
+       AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
+       AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(calibrate, 0664,
+                  adxl34x_calibrate_show, adxl34x_calibrate_store);
+
+static ssize_t adxl34x_rate_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate));
+}
+
+static ssize_t adxl34x_rate_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+       unsigned long val;
+       int error;
+
+       error = strict_strtoul(buf, 10, &val);
+       if (error)
+               return error;
+
+       mutex_lock(&ac->mutex);
+
+       ac->pdata.data_rate = RATE(val);
+       AC_WRITE(ac, BW_RATE,
+                ac->pdata.data_rate |
+                       (ac->pdata.low_power_mode ? LOW_POWER : 0));
+
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store);
+
+static ssize_t adxl34x_autosleep_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n",
+               ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0);
+}
+
+static ssize_t adxl34x_autosleep_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+       unsigned long val;
+       int error;
+
+       error = strict_strtoul(buf, 10, &val);
+       if (error)
+               return error;
+
+       mutex_lock(&ac->mutex);
+
+       if (val)
+               ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
+       else
+               ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK);
+
+       if (!ac->disabled && !ac->suspended && ac->opened)
+               AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(autosleep, 0664,
+                  adxl34x_autosleep_show, adxl34x_autosleep_store);
+
+static ssize_t adxl34x_position_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+       ssize_t count;
+
+       mutex_lock(&ac->mutex);
+       count = sprintf(buf, "(%d, %d, %d)\n",
+                       ac->saved.x, ac->saved.y, ac->saved.z);
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
+
+#ifdef ADXL_DEBUG
+static ssize_t adxl34x_write_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct adxl34x *ac = dev_get_drvdata(dev);
+       unsigned long val;
+       int error;
+
+       /*
+        * This allows basic ADXL register write access for debug purposes.
+        */
+       error = strict_strtoul(buf, 16, &val);
+       if (error)
+               return error;
+
+       mutex_lock(&ac->mutex);
+       AC_WRITE(ac, val >> 8, val & 0xFF);
+       mutex_unlock(&ac->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store);
+#endif
+
+static struct attribute *adxl34x_attributes[] = {
+       &dev_attr_disable.attr,
+       &dev_attr_calibrate.attr,
+       &dev_attr_rate.attr,
+       &dev_attr_autosleep.attr,
+       &dev_attr_position.attr,
+#ifdef ADXL_DEBUG
+       &dev_attr_write.attr,
+#endif
+       NULL
+};
+
+static const struct attribute_group adxl34x_attr_group = {
+       .attrs = adxl34x_attributes,
+};
+
+static int adxl34x_input_open(struct input_dev *input)
+{
+       struct adxl34x *ac = input_get_drvdata(input);
+
+       mutex_lock(&ac->mutex);
+
+       if (!ac->suspended && !ac->disabled)
+               __adxl34x_enable(ac);
+
+       ac->opened = true;
+
+       mutex_unlock(&ac->mutex);
+
+       return 0;
+}
+
+static void adxl34x_input_close(struct input_dev *input)
+{
+       struct adxl34x *ac = input_get_drvdata(input);
+
+       mutex_lock(&ac->mutex);
+
+       if (!ac->suspended && !ac->disabled)
+               __adxl34x_disable(ac);
+
+       ac->opened = false;
+
+       mutex_unlock(&ac->mutex);
+}
+
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+                             bool fifo_delay_default,
+                             const struct adxl34x_bus_ops *bops)
+{
+       struct adxl34x *ac;
+       struct input_dev *input_dev;
+       const struct adxl34x_platform_data *pdata;
+       int err, range, i;
+       unsigned char revid;
+
+       if (!irq) {
+               dev_err(dev, "no IRQ?\n");
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ac || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ac->fifo_delay = fifo_delay_default;
+
+       pdata = dev->platform_data;
+       if (!pdata) {
+               dev_dbg(dev,
+                       "No platfrom data: Using default initialization\n");
+               pdata = &adxl34x_default_init;
+       }
+
+       ac->pdata = *pdata;
+       pdata = &ac->pdata;
+
+       ac->input = input_dev;
+       ac->disabled = true;
+       ac->dev = dev;
+       ac->irq = irq;
+       ac->bops = bops;
+
+       mutex_init(&ac->mutex);
+
+       input_dev->name = "ADXL34x accelerometer";
+       revid = ac->bops->read(dev, DEVID);
+
+       switch (revid) {
+       case ID_ADXL345:
+               ac->model = 345;
+               break;
+       case ID_ADXL346:
+               ac->model = 346;
+               break;
+       default:
+               dev_err(dev, "Failed to probe %s\n", input_dev->name);
+               err = -ENODEV;
+               goto err_free_mem;
+       }
+
+       snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
+
+       input_dev->phys = ac->phys;
+       input_dev->dev.parent = dev;
+       input_dev->id.product = ac->model;
+       input_dev->id.bustype = bops->bustype;
+       input_dev->open = adxl34x_input_open;
+       input_dev->close = adxl34x_input_close;
+
+       input_set_drvdata(input_dev, ac);
+
+       __set_bit(ac->pdata.ev_type, input_dev->evbit);
+
+       if (ac->pdata.ev_type == EV_REL) {
+               __set_bit(REL_X, input_dev->relbit);
+               __set_bit(REL_Y, input_dev->relbit);
+               __set_bit(REL_Z, input_dev->relbit);
+       } else {
+               /* EV_ABS */
+               __set_bit(ABS_X, input_dev->absbit);
+               __set_bit(ABS_Y, input_dev->absbit);
+               __set_bit(ABS_Z, input_dev->absbit);
+
+               if (pdata->data_range & FULL_RES)
+                       range = ADXL_FULLRES_MAX_VAL;   /* Signed 13-bit */
+               else
+                       range = ADXL_FIXEDRES_MAX_VAL;  /* Signed 10-bit */
+
+               input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3);
+               input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3);
+               input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
+       }
+
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
+       __set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
+       __set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
+
+       if (pdata->ev_code_ff) {
+               ac->int_mask = FREE_FALL;
+               __set_bit(pdata->ev_code_ff, input_dev->keybit);
+       }
+
+       if (pdata->ev_code_act_inactivity)
+               __set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
+
+       ac->int_mask |= ACTIVITY | INACTIVITY;
+
+       if (pdata->watermark) {
+               ac->int_mask |= WATERMARK;
+               if (!FIFO_MODE(pdata->fifo_mode))
+                       ac->pdata.fifo_mode |= FIFO_STREAM;
+       } else {
+               ac->int_mask |= DATA_READY;
+       }
+
+       if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+               ac->int_mask |= SINGLE_TAP | DOUBLE_TAP;
+
+       if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
+               ac->fifo_delay = false;
+
+       ac->bops->write(dev, POWER_CTL, 0);
+
+       err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
+                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                  dev_name(dev), ac);
+       if (err) {
+               dev_err(dev, "irq %d busy?\n", ac->irq);
+               goto err_free_mem;
+       }
+
+       err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
+       if (err)
+               goto err_free_irq;
+
+       err = input_register_device(input_dev);
+       if (err)
+               goto err_remove_attr;
+
+       AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+       AC_WRITE(ac, OFSX, pdata->x_axis_offset);
+       ac->hwcal.x = pdata->x_axis_offset;
+       AC_WRITE(ac, OFSY, pdata->y_axis_offset);
+       ac->hwcal.y = pdata->y_axis_offset;
+       AC_WRITE(ac, OFSZ, pdata->z_axis_offset);
+       ac->hwcal.z = pdata->z_axis_offset;
+       AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+       AC_WRITE(ac, DUR, pdata->tap_duration);
+       AC_WRITE(ac, LATENT, pdata->tap_latency);
+       AC_WRITE(ac, WINDOW, pdata->tap_window);
+       AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold);
+       AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold);
+       AC_WRITE(ac, TIME_INACT, pdata->inactivity_time);
+       AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold);
+       AC_WRITE(ac, TIME_FF, pdata->free_fall_time);
+       AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control);
+       AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control);
+       AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) |
+                (pdata->low_power_mode ? LOW_POWER : 0));
+       AC_WRITE(ac, DATA_FORMAT, pdata->data_range);
+       AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
+                       SAMPLES(pdata->watermark));
+
+       if (pdata->use_int2) {
+               /* Map all INTs to INT2 */
+               AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
+       } else {
+               /* Map all INTs to INT1 */
+               AC_WRITE(ac, INT_MAP, 0);
+       }
+
+       if (ac->model == 346 && ac->pdata.orientation_enable) {
+               AC_WRITE(ac, ORIENT_CONF,
+                       ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
+                       ORIENT_DIVISOR(ac->pdata.divisor_length));
+
+               ac->orient2d_saved = 1234;
+               ac->orient3d_saved = 1234;
+
+               if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
+                       for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
+                               __set_bit(pdata->ev_codes_orient_3d[i],
+                                         input_dev->keybit);
+
+               if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
+                       for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
+                               __set_bit(pdata->ev_codes_orient_2d[i],
+                                         input_dev->keybit);
+       } else {
+               ac->pdata.orientation_enable = 0;
+       }
+
+       AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
+
+       ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
+
+       return ac;
+
+ err_remove_attr:
+       sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
+ err_free_irq:
+       free_irq(ac->irq, ac);
+ err_free_mem:
+       input_free_device(input_dev);
+       kfree(ac);
+ err_out:
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(adxl34x_probe);
+
+int adxl34x_remove(struct adxl34x *ac)
+{
+       sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
+       free_irq(ac->irq, ac);
+       input_unregister_device(ac->input);
+       dev_dbg(ac->dev, "unregistered accelerometer\n");
+       kfree(ac);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(adxl34x_remove);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
new file mode 100644 (file)
index 0000000..bbbc80f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADXL34X_H_
+#define _ADXL34X_H_
+
+struct device;
+struct adxl34x;
+
+struct adxl34x_bus_ops {
+       u16 bustype;
+       int (*read)(struct device *, unsigned char);
+       int (*read_block)(struct device *, unsigned char, int, void *);
+       int (*write)(struct device *, unsigned char, unsigned char);
+};
+
+void adxl34x_suspend(struct adxl34x *ac);
+void adxl34x_resume(struct adxl34x *ac);
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+                             bool fifo_delay_default,
+                             const struct adxl34x_bus_ops *bops);
+int adxl34x_remove(struct adxl34x *ac);
+
+#endif
index dfaa9a045ed8a9378ad74030f0bc87dfd5dc8f2e..601f7372f9c47e7eb171f2449619f66a2a0d5713 100644 (file)
@@ -21,6 +21,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -60,12 +62,11 @@ static acpi_status acpi_atlas_button_handler(u32 function,
                input_report_key(input_dev, atlas_keymap[code], key_down);
                input_sync(input_dev);
 
-               status = 0;
+               status = AE_OK;
        } else {
-               printk(KERN_WARNING "atlas: shrugged on unexpected function"
-                       ":function=%x,address=%lx,value=%x\n",
+               pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
                        function, (unsigned long)address, (u32)*value);
-               status = -EINVAL;
+               status = AE_BAD_PARAMETER;
        }
 
        return status;
@@ -79,7 +80,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
 
        input_dev = input_allocate_device();
        if (!input_dev) {
-               printk(KERN_ERR "atlas: unable to allocate input device\n");
+               pr_err("unable to allocate input device\n");
                return -ENOMEM;
        }
 
@@ -102,7 +103,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
 
        err = input_register_device(input_dev);
        if (err) {
-               printk(KERN_ERR "atlas: couldn't register input device\n");
+               pr_err("couldn't register input device\n");
                input_free_device(input_dev);
                return err;
        }
@@ -112,12 +113,12 @@ static int atlas_acpi_button_add(struct acpi_device *device)
                                0x81, &acpi_atlas_button_handler,
                                &acpi_atlas_button_setup, device);
        if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+               pr_err("error installing addr spc handler\n");
                input_unregister_device(input_dev);
-               status = -EINVAL;
+               err = -EINVAL;
        }
 
-       return status;
+       return err;
 }
 
 static int atlas_acpi_button_remove(struct acpi_device *device, int type)
@@ -126,14 +127,12 @@ static int atlas_acpi_button_remove(struct acpi_device *device, int type)
 
        status = acpi_remove_address_space_handler(device->handle,
                                0x81, &acpi_atlas_button_handler);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
-               status = -EINVAL;
-       }
+       if (ACPI_FAILURE(status))
+               pr_err("error removing addr spc handler\n");
 
        input_unregister_device(input_dev);
 
-       return status;
+       return 0;
 }
 
 static const struct acpi_device_id atlas_device_ids[] = {
@@ -145,6 +144,7 @@ MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 static struct acpi_driver atlas_acpi_driver = {
        .name   = ACPI_ATLAS_NAME,
        .class  = ACPI_ATLAS_CLASS,
+       .owner  = THIS_MODULE,
        .ids    = atlas_device_ids,
        .ops    = {
                .add    = atlas_acpi_button_add,
@@ -154,18 +154,10 @@ static struct acpi_driver atlas_acpi_driver = {
 
 static int __init atlas_acpi_init(void)
 {
-       int result;
-
        if (acpi_disabled)
                return -ENODEV;
 
-       result = acpi_bus_register_driver(&atlas_acpi_driver);
-       if (result < 0) {
-               printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
-               return -ENODEV;
-       }
-
-       return 0;
+       return acpi_bus_register_driver(&atlas_acpi_driver);
 }
 
 static void __exit atlas_acpi_exit(void)
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
new file mode 100644 (file)
index 0000000..57c294f
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  PWM beeper 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.
+ *
+ *  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/input.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+struct pwm_beeper {
+       struct input_dev *input;
+       struct pwm_device *pwm;
+       unsigned long period;
+};
+
+#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
+
+static int pwm_beeper_event(struct input_dev *input,
+                           unsigned int type, unsigned int code, int value)
+{
+       int ret = 0;
+       struct pwm_beeper *beeper = input_get_drvdata(input);
+       unsigned long period;
+
+       if (type != EV_SND || value < 0)
+               return -EINVAL;
+
+       switch (code) {
+       case SND_BELL:
+               value = value ? 1000 : 0;
+               break;
+       case SND_TONE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (value == 0) {
+               pwm_config(beeper->pwm, 0, 0);
+               pwm_disable(beeper->pwm);
+       } else {
+               period = HZ_TO_NANOSECONDS(value);
+               ret = pwm_config(beeper->pwm, period / 2, period);
+               if (ret)
+                       return ret;
+               ret = pwm_enable(beeper->pwm);
+               if (ret)
+                       return ret;
+               beeper->period = period;
+       }
+
+       return 0;
+}
+
+static int __devinit pwm_beeper_probe(struct platform_device *pdev)
+{
+       unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
+       struct pwm_beeper *beeper;
+       int error;
+
+       beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
+       if (!beeper)
+               return -ENOMEM;
+
+       beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+
+       if (IS_ERR(beeper->pwm)) {
+               error = PTR_ERR(beeper->pwm);
+               dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
+               goto err_free;
+       }
+
+       beeper->input = input_allocate_device();
+       if (!beeper->input) {
+               dev_err(&pdev->dev, "Failed to allocate input device\n");
+               error = -ENOMEM;
+               goto err_pwm_free;
+       }
+       beeper->input->dev.parent = &pdev->dev;
+
+       beeper->input->name = "pwm-beeper";
+       beeper->input->phys = "pwm/input0";
+       beeper->input->id.bustype = BUS_HOST;
+       beeper->input->id.vendor = 0x001f;
+       beeper->input->id.product = 0x0001;
+       beeper->input->id.version = 0x0100;
+
+       beeper->input->evbit[0] = BIT(EV_SND);
+       beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
+
+       beeper->input->event = pwm_beeper_event;
+
+       input_set_drvdata(beeper->input, beeper);
+
+       error = input_register_device(beeper->input);
+       if (error) {
+               dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+               goto err_input_free;
+       }
+
+       platform_set_drvdata(pdev, beeper);
+
+       return 0;
+
+err_input_free:
+       input_free_device(beeper->input);
+err_pwm_free:
+       pwm_free(beeper->pwm);
+err_free:
+       kfree(beeper);
+
+       return error;
+}
+
+static int __devexit pwm_beeper_remove(struct platform_device *pdev)
+{
+       struct pwm_beeper *beeper = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       input_unregister_device(beeper->input);
+
+       pwm_disable(beeper->pwm);
+       pwm_free(beeper->pwm);
+
+       kfree(beeper);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pwm_beeper_suspend(struct device *dev)
+{
+       struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+       if (beeper->period)
+               pwm_disable(beeper->pwm);
+
+       return 0;
+}
+
+static int pwm_beeper_resume(struct device *dev)
+{
+       struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+       if (beeper->period) {
+               pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+               pwm_enable(beeper->pwm);
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+                        pwm_beeper_suspend, pwm_beeper_resume);
+
+#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
+#else
+#define PWM_BEEPER_PM_OPS NULL
+#endif
+
+static struct platform_driver pwm_beeper_driver = {
+       .probe  = pwm_beeper_probe,
+       .remove = __devexit_p(pwm_beeper_remove),
+       .driver = {
+               .name   = "pwm-beeper",
+               .owner  = THIS_MODULE,
+               .pm     = PWM_BEEPER_PM_OPS,
+       },
+};
+
+static int __init pwm_beeper_init(void)
+{
+       return platform_driver_register(&pwm_beeper_driver);
+}
+module_init(pwm_beeper_init);
+
+static void __exit pwm_beeper_exit(void)
+{
+       platform_driver_unregister(&pwm_beeper_driver);
+}
+module_exit(pwm_beeper_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PWM beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-beeper");
index e9069b87fde235f10ee810a9cdfb3eb79ed89df5..f16972bddca473b54f8388fe6ba2709b0b65dd77 100644 (file)
@@ -52,7 +52,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
        return IRQ_HANDLED;
 }
 
-static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
+static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
 {
        struct input_dev *pwr;
        int irq = platform_get_irq(pdev, 0);
@@ -95,7 +95,7 @@ free_input_dev:
        return err;
 }
 
-static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
+static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
 {
        struct input_dev *pwr = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
@@ -106,9 +106,8 @@ static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver twl4030_pwrbutton_driver = {
-       .probe          = twl4030_pwrbutton_probe,
-       .remove         = __devexit_p(twl4030_pwrbutton_remove),
+static struct platform_driver twl4030_pwrbutton_driver = {
+       .remove         = __exit_p(twl4030_pwrbutton_remove),
        .driver         = {
                .name   = "twl4030_pwrbutton",
                .owner  = THIS_MODULE,
@@ -117,7 +116,8 @@ struct platform_driver twl4030_pwrbutton_driver = {
 
 static int __init twl4030_pwrbutton_init(void)
 {
-       return platform_driver_register(&twl4030_pwrbutton_driver);
+       return platform_driver_probe(&twl4030_pwrbutton_driver,
+                       twl4030_pwrbutton_probe);
 }
 module_init(twl4030_pwrbutton_init);
 
index 4dac8b79fcd4fc50ad1908ce3ae368cdd56085ed..12501de0c5cd36bbcc425abd84f0276607d5cbf9 100644 (file)
@@ -1347,7 +1347,7 @@ static int __init wb_module_init(void)
 
        err = map_bios();
        if (err)
-               return err;
+               goto err_free_keymap;
 
        err = platform_driver_register(&wistron_driver);
        if (err)
@@ -1371,6 +1371,8 @@ static int __init wb_module_init(void)
        platform_driver_unregister(&wistron_driver);
  err_unmap_bios:
        unmap_bios();
+ err_free_keymap:
+       kfree(keymap);
 
        return err;
 }
index 6dedded272228131c4a047fa43c0f667215e5370..ea67c49146a3a03280ee8719c362c41d8033c743 100644 (file)
@@ -312,6 +312,8 @@ static void setup_events_to_report(struct input_dev *input_dev,
        __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
        __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
        __set_bit(BTN_LEFT, input_dev->keybit);
+
+       input_set_events_per_packet(input_dev, 60);
 }
 
 /* report button data as logical button state */
@@ -580,23 +582,30 @@ exit:
  */
 static int bcm5974_start_traffic(struct bcm5974 *dev)
 {
-       if (bcm5974_wellspring_mode(dev, true)) {
+       int error;
+
+       error = bcm5974_wellspring_mode(dev, true);
+       if (error) {
                dprintk(1, "bcm5974: mode switch failed\n");
-               goto error;
+               goto err_out;
        }
 
-       if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
-               goto error;
+       error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
+       if (error)
+               goto err_reset_mode;
 
-       if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
+       error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
+       if (error)
                goto err_kill_bt;
 
        return 0;
 
 err_kill_bt:
        usb_kill_urb(dev->bt_urb);
-error:
-       return -EIO;
+err_reset_mode:
+       bcm5974_wellspring_mode(dev, false);
+err_out:
+       return error;
 }
 
 static void bcm5974_pause_traffic(struct bcm5974 *dev)
index 705589dc9ac50678f080f8b6a86dcc8443a573fb..8c324403b9f2567a64f720ee41bf57d9d9648c9c 100644 (file)
@@ -502,7 +502,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
        }
        input_report_abs(dev, ABS_PRESSURE, hw.z);
 
-       input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+       if (SYN_CAP_PALMDETECT(priv->capabilities))
+               input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+
        input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
        input_report_key(dev, BTN_LEFT, hw.left);
        input_report_key(dev, BTN_RIGHT, hw.right);
@@ -602,7 +604,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
        input_set_abs_params(dev, ABS_Y,
                             YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
        input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
-       __set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+       if (SYN_CAP_PALMDETECT(priv->capabilities))
+               input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
 
        __set_bit(EV_KEY, dev->evbit);
        __set_bit(BTN_TOUCH, dev->keybit);
index f34b22bce4ffb9ba9b2d5af62a237eda03f6241c..d8f68f77007b6c1429b1c821509914bd10ee55a9 100644 (file)
@@ -57,7 +57,6 @@ struct mousedev_hw_data {
 };
 
 struct mousedev {
-       int exist;
        int open;
        int minor;
        struct input_handle handle;
@@ -66,6 +65,7 @@ struct mousedev {
        spinlock_t client_lock; /* protects client_list */
        struct mutex mutex;
        struct device dev;
+       bool exist;
 
        struct list_head mixdev_node;
        int mixdev_open;
@@ -765,10 +765,15 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 {
        struct mousedev_client *client = file->private_data;
        struct mousedev *mousedev = client->mousedev;
+       unsigned int mask;
 
        poll_wait(file, &mousedev->wait, wait);
-       return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
-               (mousedev->exist ? 0 : (POLLHUP | POLLERR));
+
+       mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+       if (client->ready || client->buffer)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
 }
 
 static const struct file_operations mousedev_fops = {
@@ -802,7 +807,7 @@ static void mousedev_remove_chrdev(struct mousedev *mousedev)
 static void mousedev_mark_dead(struct mousedev *mousedev)
 {
        mutex_lock(&mousedev->mutex);
-       mousedev->exist = 0;
+       mousedev->exist = false;
        mutex_unlock(&mousedev->mutex);
 }
 
@@ -862,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
                dev_set_name(&mousedev->dev, "mouse%d", minor);
 
        mousedev->minor = minor;
-       mousedev->exist = 1;
+       mousedev->exist = true;
        mousedev->handle.dev = input_get_device(dev);
        mousedev->handle.name = dev_name(&mousedev->dev);
        mousedev->handle.handler = handler;
index 2906e1b60c04009a4d16ffb743ecf4f436bb7237..f708c75d16f1d919f4e054c94437fb6e4e587866 100644 (file)
@@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void)
 {
 }
 
-#elif defined(CONFIG_SPRUCE)
-
-#define I8042_KBD_IRQ 22
-#define I8042_AUX_IRQ 21
-
-#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
-#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
-#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
-
-#define I8042_COMMAND_REG 0xff810000
-#define I8042_DATA_REG 0xff810001
-
-static inline int i8042_read_data(void)
-{
-       unsigned long kbd_data;
-
-       __raw_writel(0x00000088, 0xff500008);
-       eieio();
-
-       __raw_writel(0x03000000, 0xff50000c);
-       eieio();
-
-       asm volatile("lis     7,0xff88        \n\
-                     lswi    6,7,0x8         \n\
-                     mr      %0,6"
-                     : "=r" (kbd_data) :: "6", "7");
-
-       __raw_writel(0x00000000, 0xff50000c);
-       eieio();
-
-       return (unsigned char)(kbd_data >> 24);
-}
-
-static inline int i8042_read_status(void)
-{
-       unsigned long kbd_status;
-
-       __raw_writel(0x00000088, 0xff500008);
-       eieio();
-
-       __raw_writel(0x03000000, 0xff50000c);
-       eieio();
-
-       asm volatile("lis     7,0xff88        \n\
-                     ori     7,7,0x8         \n\
-                     lswi    6,7,0x8         \n\
-                     mr      %0,6"
-                     : "=r" (kbd_status) :: "6", "7");
-
-       __raw_writel(0x00000000, 0xff50000c);
-       eieio();
-
-       return (unsigned char)(kbd_status >> 24);
-}
-
-static inline void i8042_write_data(int val)
-{
-       *((unsigned char *)0xff810000) = (char)val;
-}
-
-static inline void i8042_write_command(int val)
-{
-       *((unsigned char *)0xff810001) = (char)val;
-}
-
-static inline int i8042_platform_init(void)
-{
-       i8042_reset = 1;
-       return 0;
-}
-
-static inline void i8042_platform_exit(void)
-{
-}
-
 #else
 
 #include "i8042-io.h"
index 6440a8f55686de28141235cf80e3a72e2742d52a..258b98b9d7c2e6b2204edce42363effbf2f66bc7 100644 (file)
@@ -861,9 +861,6 @@ static int i8042_controller_selftest(void)
        unsigned char param;
        int i = 0;
 
-       if (!i8042_reset)
-               return 0;
-
        /*
         * We try this 5 times; on some really fragile systems this does not
         * take the first time...
@@ -1020,7 +1017,8 @@ static void i8042_controller_reset(void)
  * Reset the controller if requested.
  */
 
-       i8042_controller_selftest();
+       if (i8042_reset)
+               i8042_controller_selftest();
 
 /*
  * Restore the original control register setting.
@@ -1093,24 +1091,12 @@ static void i8042_dritek_enable(void)
 
 #ifdef CONFIG_PM
 
-/*
- * Here we try to restore the original BIOS settings to avoid
- * upsetting it.
- */
-
-static int i8042_pm_reset(struct device *dev)
-{
-       i8042_controller_reset();
-
-       return 0;
-}
-
 /*
  * Here we try to reset everything back to a state we had
  * before suspending.
  */
 
-static int i8042_pm_restore(struct device *dev)
+static int i8042_controller_resume(bool force_reset)
 {
        int error;
 
@@ -1118,9 +1104,11 @@ static int i8042_pm_restore(struct device *dev)
        if (error)
                return error;
 
-       error = i8042_controller_selftest();
-       if (error)
-               return error;
+       if (i8042_reset || force_reset) {
+               error = i8042_controller_selftest();
+               if (error)
+                       return error;
+       }
 
 /*
  * Restore original CTR value and disable all ports
@@ -1162,6 +1150,28 @@ static int i8042_pm_restore(struct device *dev)
        return 0;
 }
 
+/*
+ * Here we try to restore the original BIOS settings to avoid
+ * upsetting it.
+ */
+
+static int i8042_pm_reset(struct device *dev)
+{
+       i8042_controller_reset();
+
+       return 0;
+}
+
+static int i8042_pm_resume(struct device *dev)
+{
+       /*
+        * On resume from S2R we always try to reset the controller
+        * to bring it in a sane state. (In case of S2D we expect
+        * BIOS to reset the controller for us.)
+        */
+       return i8042_controller_resume(true);
+}
+
 static int i8042_pm_thaw(struct device *dev)
 {
        i8042_interrupt(0, NULL);
@@ -1169,9 +1179,14 @@ static int i8042_pm_thaw(struct device *dev)
        return 0;
 }
 
+static int i8042_pm_restore(struct device *dev)
+{
+       return i8042_controller_resume(false);
+}
+
 static const struct dev_pm_ops i8042_pm_ops = {
        .suspend        = i8042_pm_reset,
-       .resume         = i8042_pm_restore,
+       .resume         = i8042_pm_resume,
        .thaw           = i8042_pm_thaw,
        .poweroff       = i8042_pm_reset,
        .restore        = i8042_pm_restore,
@@ -1389,9 +1404,11 @@ static int __init i8042_probe(struct platform_device *dev)
 
        i8042_platform_device = dev;
 
-       error = i8042_controller_selftest();
-       if (error)
-               return error;
+       if (i8042_reset) {
+               error = i8042_controller_selftest();
+               if (error)
+                       return error;
+       }
 
        error = i8042_controller_init();
        if (error)
index 415f6306105dba7ae722e3c5ce5706fb09109949..ce0b4608dad9c2c08cb699aa27bae0e9523a40f0 100644 (file)
@@ -158,6 +158,39 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
        return 1;
 }
 
+static int wacom_dtu_irq(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       char *data = wacom->data;
+       struct input_dev *input = wacom->input;
+       int prox = data[1] & 0x20, pressure;
+
+       dbg("wacom_dtu_irq: received report #%d", data[0]);
+
+       if (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;
+       }
+       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]));
+       input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
+       pressure = ((data[7] & 0x01) << 8) | data[6];
+       if (pressure < 0)
+               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;
+       input_report_key(input, wacom->tool[0], prox);
+       input_report_abs(input, ABS_MISC, wacom->id[0]);
+       return 1;
+}
+
 static int wacom_graphire_irq(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
@@ -845,6 +878,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                sync = wacom_ptu_irq(wacom_wac);
                break;
 
+       case DTU:
+               sync = wacom_dtu_irq(wacom_wac);
+               break;
+
        case INTUOS:
        case INTUOS3S:
        case INTUOS3:
@@ -1030,6 +1067,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
 
        case PL:
        case PTU:
+       case DTU:
                __set_bit(BTN_TOOL_PEN, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
                __set_bit(BTN_STYLUS2, input_dev->keybit);
@@ -1155,6 +1193,10 @@ static const struct wacom_features wacom_features_0xC6 =
        { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
 static const struct wacom_features wacom_features_0xC7 =
        { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
+static const struct wacom_features wacom_features_0xCE =
+       { "Wacom DTU2231",        WACOM_PKGLEN_GRAPHIRE,  47864, 27011,  511,  0, DTU };
+static const struct wacom_features wacom_features_0xF0 =
+       { "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,  0, DTU };
 static const struct wacom_features wacom_features_0xCC =
        { "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047, 63, WACOM_21UX2 };
 static const struct wacom_features wacom_features_0x90 =
@@ -1234,6 +1276,8 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xC5) },
        { USB_DEVICE_WACOM(0xC6) },
        { USB_DEVICE_WACOM(0xC7) },
+       { USB_DEVICE_WACOM(0xCE) },
+       { USB_DEVICE_WACOM(0xF0) },
        { USB_DEVICE_WACOM(0xCC) },
        { USB_DEVICE_WACOM(0x90) },
        { USB_DEVICE_WACOM(0x93) },
index 854b92092dfcb8663f29bf601adc62d40ce71d1d..99e1a54cd305fa3dce303670f44973dd82d273f9 100644 (file)
@@ -43,6 +43,7 @@ enum {
        WACOM_G4,
        PTU,
        PL,
+       DTU,
        INTUOS,
        INTUOS3S,
        INTUOS3,
index 3b9d5e2105d76d9fbfdd1a8d4cab9bf80f411b25..61f35184f76c22e92747d8f9e89c43818c095032 100644 (file)
@@ -55,37 +55,36 @@ config TOUCHSCREEN_AD7877
          To compile this driver as a module, choose M here: the
          module will be called ad7877.
 
-config TOUCHSCREEN_AD7879_I2C
-       tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
-       depends on I2C
-       select TOUCHSCREEN_AD7879
+config TOUCHSCREEN_AD7879
+       tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
        help
-         Say Y here if you have a touchscreen interface using the
-         AD7879-1/AD7889-1 controller, and your board-specific
-         initialization code includes that in its table of I2C devices.
+         Say Y here if you want to support a touchscreen interface using
+         the AD7879-1/AD7889-1 controller.
 
-         If unsure, say N (but it's safe to say "Y").
+         You should select a bus connection too.
 
          To compile this driver as a module, choose M here: the
          module will be called ad7879.
 
+config TOUCHSCREEN_AD7879_I2C
+       tristate "support I2C bus connection"
+       depends on TOUCHSCREEN_AD7879 && I2C
+       help
+         Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad7879-i2c.
+
 config TOUCHSCREEN_AD7879_SPI
-       tristate "AD7879 based touchscreens: AD7879 SPI Interface"
-       depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
-       select TOUCHSCREEN_AD7879
+       tristate "support SPI bus connection"
+       depends on TOUCHSCREEN_AD7879 && SPI_MASTER
        help
-         Say Y here if you have a touchscreen interface using the
-         AD7879/AD7889 controller, and your board-specific initialization
-         code includes that in its table of SPI devices.
+         Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
 
          If unsure, say N (but it's safe to say "Y").
 
          To compile this driver as a module, choose M here: the
-         module will be called ad7879.
-
-config TOUCHSCREEN_AD7879
-       tristate
-       default n
+         module will be called ad7879-spi.
 
 config TOUCHSCREEN_BITSY
        tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
@@ -99,6 +98,20 @@ config TOUCHSCREEN_BITSY
          To compile this driver as a module, choose M here: the
          module will be called h3600_ts_input.
 
+config TOUCHSCREEN_CY8CTMG110
+       tristate "cy8ctmg110 touchscreen"
+       depends on I2C
+       depends on GPIOLIB
+
+       help
+         Say Y here if you have a cy8ctmg110 capacitive touchscreen on
+         an AAVA device.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cy8ctmg110_ts.
+
 config TOUCHSCREEN_DA9034
        tristate "Touchscreen support for Dialog Semiconductor DA9034"
        depends on PMIC_DA903X
@@ -292,6 +305,18 @@ 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
@@ -540,9 +565,9 @@ config TOUCHSCREEN_USB_ZYTRONIC
        bool "Zytronic controller" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
-config TOUCHSCREEN_USB_ETT_TC5UH
+config TOUCHSCREEN_USB_ETT_TC45USB
        default y
-       bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
+       bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_NEXIO
index 497964a7a2146dfe39f27361cd134480b35f2c78..bd6f30b4ff702d1dfcf28145eb0be30d926bf41d 100644 (file)
@@ -9,9 +9,13 @@ wm97xx-ts-y := wm97xx-core.o
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)     += 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)       += ad7877.o
 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_TSADCC) += atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)                += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)   += cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034)       += da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)      += dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)    += hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)                += gunze.o
@@ -30,6 +34,7 @@ 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_TOUCHIT213)   += touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
@@ -38,7 +43,6 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2007)     += tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)  += wacom_w8001.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)       += wm97xx-ts.o
-obj-$(CONFIG_TOUCHSCREEN_DA9034)       += da9034-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
new file mode 100644 (file)
index 0000000..d82a38e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * AD7879-1/AD7889-1 touchscreen (I2C bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>       /* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID           0x79    /* AD7879-1/AD7889-1 */
+
+#ifdef CONFIG_PM
+static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+       struct ad7879 *ts = i2c_get_clientdata(client);
+
+       ad7879_suspend(ts);
+
+       return 0;
+}
+
+static int ad7879_i2c_resume(struct i2c_client *client)
+{
+       struct ad7879 *ts = i2c_get_clientdata(client);
+
+       ad7879_resume(ts);
+
+       return 0;
+}
+#else
+# define ad7879_i2c_suspend NULL
+# define ad7879_i2c_resume  NULL
+#endif
+
+/* All registers are word-sized.
+ * AD7879 uses a high-byte first convention.
+ */
+static int ad7879_i2c_read(struct device *dev, u8 reg)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static int ad7879_i2c_multi_read(struct device *dev,
+                                u8 first_reg, u8 count, u16 *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       u8 idx;
+
+       i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
+
+       for (idx = 0; idx < count; ++idx)
+               buf[idx] = swab16(buf[idx]);
+
+       return 0;
+}
+
+static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
+       .bustype        = BUS_I2C,
+       .read           = ad7879_i2c_read,
+       .multi_read     = ad7879_i2c_multi_read,
+       .write          = ad7879_i2c_write,
+};
+
+static int __devinit ad7879_i2c_probe(struct i2c_client *client,
+                                     const struct i2c_device_id *id)
+{
+       struct ad7879 *ts;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+               return -EIO;
+       }
+
+       ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
+                         &ad7879_i2c_bus_ops);
+       if (IS_ERR(ts))
+               return PTR_ERR(ts);
+
+       i2c_set_clientdata(client, ts);
+
+       return 0;
+}
+
+static int __devexit ad7879_i2c_remove(struct i2c_client *client)
+{
+       struct ad7879 *ts = i2c_get_clientdata(client);
+
+       ad7879_remove(ts);
+
+       return 0;
+}
+
+static const struct i2c_device_id ad7879_id[] = {
+       { "ad7879", 0 },
+       { "ad7889", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ad7879_id);
+
+static struct i2c_driver ad7879_i2c_driver = {
+       .driver = {
+               .name   = "ad7879",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad7879_i2c_probe,
+       .remove         = __devexit_p(ad7879_i2c_remove),
+       .suspend        = ad7879_i2c_suspend,
+       .resume         = ad7879_i2c_resume,
+       .id_table       = ad7879_id,
+};
+
+static int __init ad7879_i2c_init(void)
+{
+       return i2c_add_driver(&ad7879_i2c_driver);
+}
+module_init(ad7879_i2c_init);
+
+static void __exit ad7879_i2c_exit(void)
+{
+       i2c_del_driver(&ad7879_i2c_driver);
+}
+module_exit(ad7879_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad7879");
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
new file mode 100644 (file)
index 0000000..59c6e68
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * AD7879/AD7889 touchscreen (SPI bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>       /* BUS_SPI */
+#include <linux/spi/spi.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID           0x7A    /* AD7879/AD7889 */
+
+#define MAX_SPI_FREQ_HZ      5000000
+#define AD7879_CMD_MAGIC     0xE000
+#define AD7879_CMD_READ      (1 << 10)
+#define AD7879_CMD(reg)      (AD7879_CMD_MAGIC | ((reg) & 0xF))
+#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)
+{
+       struct ad7879 *ts = spi_get_drvdata(spi);
+
+       ad7879_suspend(ts);
+
+       return 0;
+}
+
+static int ad7879_spi_resume(struct spi_device *spi)
+{
+       struct ad7879 *ts = spi_get_drvdata(spi);
+
+       ad7879_resume(ts);
+
+       return 0;
+}
+#else
+# define ad7879_spi_suspend NULL
+# define ad7879_spi_resume  NULL
+#endif
+
+/*
+ * ad7879_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done in ad7879_collect().
+ */
+
+static int ad7879_spi_xfer(struct spi_device *spi,
+                          u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
+{
+       struct spi_message msg;
+       struct spi_transfer *xfers;
+       void *spi_data;
+       u16 *command;
+       u16 *_rx_buf = _rx_buf; /* shut gcc up */
+       u8 idx;
+       int ret;
+
+       xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
+       if (!spi_data)
+               return -ENOMEM;
+
+       spi_message_init(&msg);
+
+       command = spi_data;
+       command[0] = cmd;
+       if (count == 1) {
+               /* ad7879_spi_{read,write} gave us buf on stack */
+               command[1] = *tx_buf;
+               tx_buf = &command[1];
+               _rx_buf = rx_buf;
+               rx_buf = &command[2];
+       }
+
+       ++xfers;
+       xfers[0].tx_buf = command;
+       xfers[0].len = 2;
+       spi_message_add_tail(&xfers[0], &msg);
+       ++xfers;
+
+       for (idx = 0; idx < count; ++idx) {
+               if (rx_buf)
+                       xfers[idx].rx_buf = &rx_buf[idx];
+               if (tx_buf)
+                       xfers[idx].tx_buf = &tx_buf[idx];
+               xfers[idx].len = 2;
+               spi_message_add_tail(&xfers[idx], &msg);
+       }
+
+       ret = spi_sync(spi, &msg);
+
+       if (count == 1)
+               _rx_buf[0] = command[2];
+
+       kfree(spi_data);
+
+       return ret;
+}
+
+static int ad7879_spi_multi_read(struct device *dev,
+                                u8 first_reg, u8 count, u16 *buf)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
+}
+
+static int ad7879_spi_read(struct device *dev, u8 reg)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u16 ret, dummy;
+
+       return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
+}
+
+static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u16 dummy;
+
+       return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
+}
+
+static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
+       .bustype        = BUS_SPI,
+       .read           = ad7879_spi_read,
+       .multi_read     = ad7879_spi_multi_read,
+       .write          = ad7879_spi_write,
+};
+
+static int __devinit ad7879_spi_probe(struct spi_device *spi)
+{
+       struct ad7879 *ts;
+       int err;
+
+       /* don't exceed max specified SPI CLK frequency */
+       if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+               dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+               return -EINVAL;
+       }
+
+       spi->bits_per_word = 16;
+       err = spi_setup(spi);
+       if (err) {
+               dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
+               return err;
+       }
+
+       ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
+       if (IS_ERR(ts))
+               return PTR_ERR(ts);
+
+       spi_set_drvdata(spi, ts);
+
+       return 0;
+}
+
+static int __devexit ad7879_spi_remove(struct spi_device *spi)
+{
+       struct ad7879 *ts = spi_get_drvdata(spi);
+
+       ad7879_remove(ts);
+       spi_set_drvdata(spi, NULL);
+
+       return 0;
+}
+
+static struct spi_driver ad7879_spi_driver = {
+       .driver = {
+               .name   = "ad7879",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .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)
+{
+       return spi_register_driver(&ad7879_spi_driver);
+}
+module_init(ad7879_spi_init);
+
+static void __exit ad7879_spi_exit(void)
+{
+       spi_unregister_driver(&ad7879_spi_driver);
+}
+module_exit(ad7879_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad7879");
index 4b32fb4704cd37b24f67c84db53de4ed431320c8..ba6f0bd1e762e494961f6eab23204fb37eff63c0 100644 (file)
@@ -1,25 +1,9 @@
 /*
- * Copyright (C) 2008-2009 Michael Hennerich, Analog Devices Inc.
+ * AD7879/AD7889 based touchscreen and GPIO driver
  *
- * Description:        AD7879/AD7889 based touchscreen, and GPIO driver
- *             (I2C/SPI Interface)
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
  *
- * Bugs:        Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  *
  * History:
  * Copyright (c) 2005 David Brownell
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 
 #include <linux/spi/ad7879.h>
+#include "ad7879.h"
 
 #define AD7879_REG_ZEROS               0
 #define AD7879_REG_CTRL1               1
@@ -120,30 +104,19 @@ enum {
 #define        MAX_12BIT                       ((1<<12)-1)
 #define        TS_PEN_UP_TIMEOUT               msecs_to_jiffies(50)
 
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define AD7879_DEVID           0x7A
-typedef struct spi_device      bus_device;
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-#define AD7879_DEVID           0x79
-typedef struct i2c_client      bus_device;
-#endif
-
 struct ad7879 {
-       bus_device              *bus;
+       const struct ad7879_bus_ops *bops;
+
+       struct device           *dev;
        struct input_dev        *input;
-       struct work_struct      work;
        struct timer_list       timer;
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip        gc;
-#endif
        struct mutex            mutex;
-       unsigned                disabled:1;     /* P: mutex */
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-       struct spi_message      msg;
-       struct spi_transfer     xfer[AD7879_NR_SENSE + 1];
-       u16                     cmd;
 #endif
+       unsigned int            irq;
+       bool                    disabled;       /* P: input->mutex */
+       bool                    suspended;      /* P: input->mutex */
        u16                     conversion_data[AD7879_NR_SENSE];
        char                    phys[32];
        u8                      first_conversion_delay;
@@ -158,11 +131,22 @@ struct ad7879 {
        u16                     cmd_crtl3;
 };
 
-static int ad7879_read(bus_device *, u8);
-static int ad7879_write(bus_device *, u8, u16);
-static void ad7879_collect(struct ad7879 *);
+static int ad7879_read(struct ad7879 *ts, u8 reg)
+{
+       return ts->bops->read(ts->dev, reg);
+}
+
+static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
+{
+       return ts->bops->multi_read(ts->dev, first_reg, count, buf);
+}
 
-static void ad7879_report(struct ad7879 *ts)
+static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
+{
+       return ts->bops->write(ts->dev, reg, val);
+}
+
+static int ad7879_report(struct ad7879 *ts)
 {
        struct input_dev *input_dev = ts->input;
        unsigned Rt;
@@ -175,12 +159,14 @@ static void ad7879_report(struct ad7879 *ts)
 
        /*
         * The samples processed here are already preprocessed by the AD7879.
-        * The preprocessing function consists of a median and an averaging filter.
-        * The combination of these two techniques provides a robust solution,
-        * discarding the spurious noise in the signal and keeping only the data of interest.
-        * The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
-        * Other user-programmable conversion controls include variable acquisition time,
-        * and first conversion delay. Up to 16 averages can be taken per conversion.
+        * The preprocessing function consists of a median and an averaging
+        * filter.  The combination of these two techniques provides a robust
+        * solution, discarding the spurious noise in the signal and keeping
+        * only the data of interest.  The size of both filters is
+        * programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
+        * user-programmable conversion controls include variable acquisition
+        * time, and first conversion delay. Up to 16 averages can be taken
+        * per conversion.
         */
 
        if (likely(x && z1)) {
@@ -189,21 +175,17 @@ static void ad7879_report(struct ad7879 *ts)
                Rt /= z1;
                Rt = (Rt + 2047) >> 12;
 
+               if (!timer_pending(&ts->timer))
+                       input_report_key(input_dev, BTN_TOUCH, 1);
+
                input_report_abs(input_dev, ABS_X, x);
                input_report_abs(input_dev, ABS_Y, y);
                input_report_abs(input_dev, ABS_PRESSURE, Rt);
                input_sync(input_dev);
+               return 0;
        }
-}
-
-static void ad7879_work(struct work_struct *work)
-{
-       struct ad7879 *ts = container_of(work, struct ad7879, work);
 
-       /* use keventd context to read the result registers */
-       ad7879_collect(ts);
-       ad7879_report(ts);
-       mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+       return -EINVAL;
 }
 
 static void ad7879_ts_event_release(struct ad7879 *ts)
@@ -211,6 +193,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
        struct input_dev *input_dev = ts->input;
 
        input_report_abs(input_dev, ABS_PRESSURE, 0);
+       input_report_key(input_dev, BTN_TOUCH, 0);
        input_sync(input_dev);
 }
 
@@ -225,56 +208,98 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
 {
        struct ad7879 *ts = handle;
 
-       /* The repeated conversion sequencer controlled by TMR kicked off too fast.
-        * We ignore the last and process the sample sequence currently in the queue.
-        * It can't be older than 9.4ms
-        */
+       ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
 
-       if (!work_pending(&ts->work))
-               schedule_work(&ts->work);
+       if (!ad7879_report(ts))
+               mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
 
        return IRQ_HANDLED;
 }
 
-static void ad7879_setup(struct ad7879 *ts)
+static void __ad7879_enable(struct ad7879 *ts)
 {
-       ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
-       ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
-       ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+       ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+       ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
+       ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
+
+       enable_irq(ts->irq);
 }
 
-static void ad7879_disable(struct ad7879 *ts)
+static void __ad7879_disable(struct ad7879 *ts)
 {
-       mutex_lock(&ts->mutex);
+       disable_irq(ts->irq);
+
+       if (del_timer_sync(&ts->timer))
+               ad7879_ts_event_release(ts);
+
+       ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN));
+}
 
-       if (!ts->disabled) {
 
-               ts->disabled = 1;
-               disable_irq(ts->bus->irq);
+static int ad7879_open(struct input_dev *input)
+{
+       struct ad7879 *ts = input_get_drvdata(input);
 
-               cancel_work_sync(&ts->work);
+       /* protected by input->mutex */
+       if (!ts->disabled && !ts->suspended)
+               __ad7879_enable(ts);
 
-               if (del_timer_sync(&ts->timer))
-                       ad7879_ts_event_release(ts);
+       return 0;
+}
 
-               ad7879_write(ts->bus, AD7879_REG_CTRL2,
-                            AD7879_PM(AD7879_PM_SHUTDOWN));
-       }
+static void ad7879_close(struct input_dev* input)
+{
+       struct ad7879 *ts = input_get_drvdata(input);
 
-       mutex_unlock(&ts->mutex);
+       /* protected by input->mutex */
+       if (!ts->disabled && !ts->suspended)
+               __ad7879_disable(ts);
 }
 
-static void ad7879_enable(struct ad7879 *ts)
+void ad7879_suspend(struct ad7879 *ts)
 {
-       mutex_lock(&ts->mutex);
+       mutex_lock(&ts->input->mutex);
+
+       if (!ts->suspended && !ts->disabled && ts->input->users)
+               __ad7879_disable(ts);
+
+       ts->suspended = true;
 
-       if (ts->disabled) {
-               ad7879_setup(ts);
-               ts->disabled = 0;
-               enable_irq(ts->bus->irq);
+       mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_suspend);
+
+void ad7879_resume(struct ad7879 *ts)
+{
+       mutex_lock(&ts->input->mutex);
+
+       if (ts->suspended && !ts->disabled && ts->input->users)
+               __ad7879_enable(ts);
+
+       ts->suspended = false;
+
+       mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_resume);
+
+static void ad7879_toggle(struct ad7879 *ts, bool disable)
+{
+       mutex_lock(&ts->input->mutex);
+
+       if (!ts->suspended && ts->input->users != 0) {
+
+               if (disable) {
+                       if (ts->disabled)
+                               __ad7879_enable(ts);
+               } else {
+                       if (!ts->disabled)
+                               __ad7879_disable(ts);
+               }
        }
 
-       mutex_unlock(&ts->mutex);
+       ts->disabled = disable;
+
+       mutex_unlock(&ts->input->mutex);
 }
 
 static ssize_t ad7879_disable_show(struct device *dev,
@@ -297,10 +322,7 @@ static ssize_t ad7879_disable_store(struct device *dev,
        if (error)
                return error;
 
-       if (val)
-               ad7879_disable(ts);
-       else
-               ad7879_enable(ts);
+       ad7879_toggle(ts, val);
 
        return count;
 }
@@ -325,7 +347,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
 
        mutex_lock(&ts->mutex);
        ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
-       err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+       err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
        mutex_unlock(&ts->mutex);
 
        return err;
@@ -345,7 +367,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
        else
                ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
-       err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+       err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
        mutex_unlock(&ts->mutex);
 
        return err;
@@ -357,7 +379,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
        u16 val;
 
        mutex_lock(&ts->mutex);
-       val = ad7879_read(ts->bus, AD7879_REG_CTRL2);
+       val = ad7879_read(ts, AD7879_REG_CTRL2);
        mutex_unlock(&ts->mutex);
 
        return !!(val & AD7879_GPIO_DATA);
@@ -374,16 +396,17 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
        else
                ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
-       ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+       ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
        mutex_unlock(&ts->mutex);
 }
 
-static int __devinit ad7879_gpio_add(struct device *dev)
+static int ad7879_gpio_add(struct ad7879 *ts,
+                          const struct ad7879_platform_data *pdata)
 {
-       struct ad7879 *ts = dev_get_drvdata(dev);
-       struct ad7879_platform_data *pdata = dev->platform_data;
        int ret = 0;
 
+       mutex_init(&ts->mutex);
+
        if (pdata->gpio_export) {
                ts->gc.direction_input = ad7879_gpio_direction_input;
                ts->gc.direction_output = ad7879_gpio_direction_output;
@@ -394,72 +417,75 @@ static int __devinit ad7879_gpio_add(struct device *dev)
                ts->gc.ngpio = 1;
                ts->gc.label = "AD7879-GPIO";
                ts->gc.owner = THIS_MODULE;
-               ts->gc.dev = dev;
+               ts->gc.dev = ts->dev;
 
                ret = gpiochip_add(&ts->gc);
                if (ret)
-                       dev_err(dev, "failed to register gpio %d\n",
+                       dev_err(ts->dev, "failed to register gpio %d\n",
                                ts->gc.base);
        }
 
        return ret;
 }
 
-/*
- * We mark ad7879_gpio_remove inline so there is a chance the code
- * gets discarded when not needed. We can't do __devinit/__devexit
- * markup since it is used in both probe and remove methods.
- */
-static inline void ad7879_gpio_remove(struct device *dev)
+static void ad7879_gpio_remove(struct ad7879 *ts)
 {
-       struct ad7879 *ts = dev_get_drvdata(dev);
-       struct ad7879_platform_data *pdata = dev->platform_data;
+       const struct ad7879_platform_data *pdata = ts->dev->platform_data;
        int ret;
 
        if (pdata->gpio_export) {
                ret = gpiochip_remove(&ts->gc);
                if (ret)
-                       dev_err(dev, "failed to remove gpio %d\n",
+                       dev_err(ts->dev, "failed to remove gpio %d\n",
                                ts->gc.base);
        }
 }
 #else
-static inline int ad7879_gpio_add(struct device *dev)
+static inline int ad7879_gpio_add(struct ad7879 *ts,
+                                 const struct ad7879_platform_data *pdata)
 {
        return 0;
 }
 
-static inline void ad7879_gpio_remove(struct device *dev)
+static inline void ad7879_gpio_remove(struct ad7879 *ts)
 {
 }
 #endif
 
-static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
+                           const struct ad7879_bus_ops *bops)
 {
+       struct ad7879_platform_data *pdata = dev->platform_data;
+       struct ad7879 *ts;
        struct input_dev *input_dev;
-       struct ad7879_platform_data *pdata = bus->dev.platform_data;
        int err;
        u16 revid;
 
-       if (!bus->irq) {
-               dev_err(&bus->dev, "no IRQ?\n");
-               return -ENODEV;
+       if (!irq) {
+               dev_err(dev, "no IRQ?\n");
+               err = -EINVAL;
+               goto err_out;
        }
 
        if (!pdata) {
-               dev_err(&bus->dev, "no platform data?\n");
-               return -ENODEV;
+               dev_err(dev, "no platform data?\n");
+               err = -EINVAL;
+               goto err_out;
        }
 
+       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!input_dev)
-               return -ENOMEM;
+       if (!ts || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
 
+       ts->bops = bops;
+       ts->dev = dev;
        ts->input = input_dev;
+       ts->irq = irq;
 
        setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
-       INIT_WORK(&ts->work, ad7879_work);
-       mutex_init(&ts->mutex);
 
        ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
        ts->pressure_max = pdata->pressure_max ? : ~0;
@@ -470,17 +496,26 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
        ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
        ts->median = pdata->median;
 
-       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
+       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
 
        input_dev->name = "AD7879 Touchscreen";
        input_dev->phys = ts->phys;
-       input_dev->dev.parent = &bus->dev;
+       input_dev->dev.parent = dev;
+       input_dev->id.bustype = bops->bustype;
+
+       input_dev->open = ad7879_open;
+       input_dev->close = ad7879_close;
+
+       input_set_drvdata(input_dev, ts);
 
        __set_bit(EV_ABS, input_dev->evbit);
        __set_bit(ABS_X, input_dev->absbit);
        __set_bit(ABS_Y, input_dev->absbit);
        __set_bit(ABS_PRESSURE, input_dev->absbit);
 
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+
        input_set_abs_params(input_dev, ABS_X,
                        pdata->x_min ? : 0,
                        pdata->x_max ? : MAX_12BIT,
@@ -492,17 +527,18 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
        input_set_abs_params(input_dev, ABS_PRESSURE,
                        pdata->pressure_min, pdata->pressure_max, 0, 0);
 
-       err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET);
-
+       err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
        if (err < 0) {
-               dev_err(&bus->dev, "Failed to write %s\n", input_dev->name);
+               dev_err(dev, "Failed to write %s\n", input_dev->name);
                goto err_free_mem;
        }
 
-       revid = ad7879_read(bus, AD7879_REG_REVID);
-
-       if ((revid & 0xFF) != AD7879_DEVID) {
-               dev_err(&bus->dev, "Failed to probe %s\n", input_dev->name);
+       revid = ad7879_read(ts, AD7879_REG_REVID);
+       input_dev->id.product = (revid & 0xff);
+       input_dev->id.version = revid >> 8;
+       if (input_dev->id.product != devid) {
+               dev_err(dev, "Failed to probe %s (%x vs %x)\n",
+                       input_dev->name, devid, revid);
                err = -ENODEV;
                goto err_free_mem;
        }
@@ -524,21 +560,21 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
                        AD7879_ACQ(ts->acquisition_time) |
                        AD7879_TMR(ts->pen_down_acc_interval);
 
-       ad7879_setup(ts);
-
-       err = request_irq(bus->irq, ad7879_irq,
-                         IRQF_TRIGGER_FALLING, bus->dev.driver->name, ts);
-
+       err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
+                                  IRQF_TRIGGER_FALLING,
+                                  dev_name(dev), ts);
        if (err) {
-               dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
+               dev_err(dev, "irq %d busy?\n", ts->irq);
                goto err_free_mem;
        }
 
-       err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group);
+       __ad7879_disable(ts);
+
+       err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
        if (err)
                goto err_free_irq;
 
-       err = ad7879_gpio_add(&bus->dev);
+       err = ad7879_gpio_add(ts, pdata);
        if (err)
                goto err_remove_attr;
 
@@ -546,321 +582,32 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
        if (err)
                goto err_remove_gpio;
 
-       dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
-                revid >> 8, bus->irq);
-
-       return 0;
+       return ts;
 
 err_remove_gpio:
-       ad7879_gpio_remove(&bus->dev);
+       ad7879_gpio_remove(ts);
 err_remove_attr:
-       sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
+       sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
 err_free_irq:
-       free_irq(bus->irq, ts);
+       free_irq(ts->irq, ts);
 err_free_mem:
        input_free_device(input_dev);
-
-       return err;
-}
-
-static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
-{
-       ad7879_gpio_remove(&bus->dev);
-       ad7879_disable(ts);
-       sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
-       free_irq(ts->bus->irq, ts);
-       input_unregister_device(ts->input);
-       dev_dbg(&bus->dev, "unregistered touchscreen\n");
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad7879_suspend(bus_device *bus, pm_message_t message)
-{
-       struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
-       ad7879_disable(ts);
-
-       return 0;
-}
-
-static int ad7879_resume(bus_device *bus)
-{
-       struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
-       ad7879_enable(ts);
-
-       return 0;
-}
-#else
-#define ad7879_suspend NULL
-#define ad7879_resume  NULL
-#endif
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define MAX_SPI_FREQ_HZ                5000000
-#define AD7879_CMD_MAGIC       0xE000
-#define AD7879_CMD_READ                (1 << 10)
-#define AD7879_WRITECMD(reg)   (AD7879_CMD_MAGIC | (reg & 0xF))
-#define AD7879_READCMD(reg)    (AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
-
-struct ser_req {
-       u16                     command;
-       u16                     data;
-       struct spi_message      msg;
-       struct spi_transfer     xfer[2];
-};
-
-/*
- * ad7879_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done in ad7879_collect().
- */
-
-static int ad7879_read(struct spi_device *spi, u8 reg)
-{
-       struct ser_req *req;
-       int status, ret;
-
-       req = kzalloc(sizeof *req, GFP_KERNEL);
-       if (!req)
-               return -ENOMEM;
-
-       spi_message_init(&req->msg);
-
-       req->command = (u16) AD7879_READCMD(reg);
-       req->xfer[0].tx_buf = &req->command;
-       req->xfer[0].len = 2;
-
-       req->xfer[1].rx_buf = &req->data;
-       req->xfer[1].len = 2;
-
-       spi_message_add_tail(&req->xfer[0], &req->msg);
-       spi_message_add_tail(&req->xfer[1], &req->msg);
-
-       status = spi_sync(spi, &req->msg);
-       ret = status ? : req->data;
-
-       kfree(req);
-
-       return ret;
-}
-
-static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
-{
-       struct ser_req *req;
-       int status;
-
-       req = kzalloc(sizeof *req, GFP_KERNEL);
-       if (!req)
-               return -ENOMEM;
-
-       spi_message_init(&req->msg);
-
-       req->command = (u16) AD7879_WRITECMD(reg);
-       req->xfer[0].tx_buf = &req->command;
-       req->xfer[0].len = 2;
-
-       req->data = val;
-       req->xfer[1].tx_buf = &req->data;
-       req->xfer[1].len = 2;
-
-       spi_message_add_tail(&req->xfer[0], &req->msg);
-       spi_message_add_tail(&req->xfer[1], &req->msg);
-
-       status = spi_sync(spi, &req->msg);
-
-       kfree(req);
-
-       return status;
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
-       int status = spi_sync(ts->bus, &ts->msg);
-
-       if (status)
-               dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
-}
-
-static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
-{
-       struct spi_message *m;
-       int i;
-
-       ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS);
-
-       m = &ts->msg;
-       spi_message_init(m);
-       ts->xfer[0].tx_buf = &ts->cmd;
-       ts->xfer[0].len = 2;
-
-       spi_message_add_tail(&ts->xfer[0], m);
-
-       for (i = 0; i < AD7879_NR_SENSE; i++) {
-               ts->xfer[i + 1].rx_buf = &ts->conversion_data[i];
-               ts->xfer[i + 1].len = 2;
-               spi_message_add_tail(&ts->xfer[i + 1], m);
-       }
-}
-
-static int __devinit ad7879_probe(struct spi_device *spi)
-{
-       struct ad7879 *ts;
-       int error;
-
-       /* don't exceed max specified SPI CLK frequency */
-       if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
-               dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
-               return -EINVAL;
-       }
-
-       ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
-       if (!ts)
-               return -ENOMEM;
-
-       dev_set_drvdata(&spi->dev, ts);
-       ts->bus = spi;
-
-       ad7879_setup_ts_def_msg(ts);
-
-       error = ad7879_construct(spi, ts);
-       if (error) {
-               dev_set_drvdata(&spi->dev, NULL);
-               kfree(ts);
-       }
-
-       return error;
-}
-
-static int __devexit ad7879_remove(struct spi_device *spi)
-{
-       struct ad7879 *ts = dev_get_drvdata(&spi->dev);
-
-       ad7879_destroy(spi, ts);
-       dev_set_drvdata(&spi->dev, NULL);
        kfree(ts);
-
-       return 0;
+err_out:
+       return ERR_PTR(err);
 }
+EXPORT_SYMBOL(ad7879_probe);
 
-static struct spi_driver ad7879_driver = {
-       .driver = {
-               .name   = "ad7879",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
-       },
-       .probe          = ad7879_probe,
-       .remove         = __devexit_p(ad7879_remove),
-       .suspend        = ad7879_suspend,
-       .resume         = ad7879_resume,
-};
-
-static int __init ad7879_init(void)
-{
-       return spi_register_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
-       spi_unregister_driver(&ad7879_driver);
-}
-module_exit(ad7879_exit);
-
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-
-/* All registers are word-sized.
- * AD7879 uses a high-byte first convention.
- */
-static int ad7879_read(struct i2c_client *client, u8 reg)
+void ad7879_remove(struct ad7879 *ts)
 {
-       return swab16(i2c_smbus_read_word_data(client, reg));
-}
-
-static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
-{
-       return i2c_smbus_write_word_data(client, reg, swab16(val));
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
-       int i;
-
-       for (i = 0; i < AD7879_NR_SENSE; i++)
-               ts->conversion_data[i] = ad7879_read(ts->bus,
-                                                    AD7879_REG_XPLUS + i);
-}
-
-static int __devinit ad7879_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
-{
-       struct ad7879 *ts;
-       int error;
-
-       if (!i2c_check_functionality(client->adapter,
-                                       I2C_FUNC_SMBUS_WORD_DATA)) {
-               dev_err(&client->dev, "SMBUS Word Data not Supported\n");
-               return -EIO;
-       }
-
-       ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
-       if (!ts)
-               return -ENOMEM;
-
-       i2c_set_clientdata(client, ts);
-       ts->bus = client;
-
-       error = ad7879_construct(client, ts);
-       if (error)
-               kfree(ts);
-
-       return error;
-}
-
-static int __devexit ad7879_remove(struct i2c_client *client)
-{
-       struct ad7879 *ts = dev_get_drvdata(&client->dev);
-
-       ad7879_destroy(client, ts);
+       ad7879_gpio_remove(ts);
+       sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
+       free_irq(ts->irq, ts);
+       input_unregister_device(ts->input);
        kfree(ts);
-
-       return 0;
-}
-
-static const struct i2c_device_id ad7879_id[] = {
-       { "ad7879", 0 },
-       { "ad7889", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ad7879_id);
-
-static struct i2c_driver ad7879_driver = {
-       .driver = {
-               .name   = "ad7879",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = ad7879_probe,
-       .remove         = __devexit_p(ad7879_remove),
-       .suspend        = ad7879_suspend,
-       .resume         = ad7879_resume,
-       .id_table       = ad7879_id,
-};
-
-static int __init ad7879_init(void)
-{
-       return i2c_add_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
-       i2c_del_driver(&ad7879_driver);
 }
-module_exit(ad7879_exit);
-#endif
+EXPORT_SYMBOL(ad7879_remove);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
new file mode 100644 (file)
index 0000000..6b45a27
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * AD7879/AD7889 touchscreen (bus interfaces)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD7879_H_
+#define _AD7879_H_
+
+#include <linux/types.h>
+
+struct ad7879;
+struct device;
+
+struct ad7879_bus_ops {
+       u16 bustype;
+       int (*read)(struct device *dev, u8 reg);
+       int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
+       int (*write)(struct device *dev, u8 reg, u16 val);
+};
+
+void ad7879_suspend(struct ad7879 *);
+void ad7879_resume(struct ad7879 *);
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
+                           const struct ad7879_bus_ops *bops);
+void ad7879_remove(struct ad7879 *);
+
+#endif
index a9fdf55c0238b14b4c6fa54fa257002f925d3daa..16031933a8f621266a555b09ff63979c0359ca0b 100644 (file)
@@ -68,6 +68,8 @@ struct ts_event {
        u16     y;
        u16     z1, z2;
        int     ignore;
+       u8      x_buf[3];
+       u8      y_buf[3];
 };
 
 /*
@@ -79,6 +81,8 @@ struct ads7846_packet {
        u8                      read_x, read_y, read_z1, read_z2, pwrdown;
        u16                     dummy;          /* for the pwrdown read */
        struct ts_event         tc;
+       /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
+       u8                      read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
 };
 
 struct ads7846 {
@@ -207,6 +211,14 @@ struct ser_req {
        struct spi_transfer     xfer[6];
 };
 
+struct ads7845_ser_req {
+       u8                      command[3];
+       u8                      pwrdown[3];
+       u8                      sample[3];
+       struct spi_message      msg;
+       struct spi_transfer     xfer[2];
+};
+
 static void ads7846_enable(struct ads7846 *ts);
 static void ads7846_disable(struct ads7846 *ts);
 
@@ -287,6 +299,41 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        return status;
 }
 
+static int ads7845_read12_ser(struct device *dev, unsigned command)
+{
+       struct spi_device       *spi = to_spi_device(dev);
+       struct ads7846          *ts = dev_get_drvdata(dev);
+       struct ads7845_ser_req  *req = kzalloc(sizeof *req, GFP_KERNEL);
+       int                     status;
+
+       if (!req)
+               return -ENOMEM;
+
+       spi_message_init(&req->msg);
+
+       req->command[0] = (u8) command;
+       req->xfer[0].tx_buf = req->command;
+       req->xfer[0].rx_buf = req->sample;
+       req->xfer[0].len = 3;
+       spi_message_add_tail(&req->xfer[0], &req->msg);
+
+       ts->irq_disabled = 1;
+       disable_irq(spi->irq);
+       status = spi_sync(spi, &req->msg);
+       ts->irq_disabled = 0;
+       enable_irq(spi->irq);
+
+       if (status == 0) {
+               /* BE12 value, then padding */
+               status = be16_to_cpu(*((u16 *)&req->sample[1]));
+               status = status >> 3;
+               status &= 0x0fff;
+       }
+
+       kfree(req);
+       return status;
+}
+
 #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
 
 #define SHOW(name, var, adjust) static ssize_t \
@@ -540,10 +587,17 @@ static void ads7846_rx(void *ads)
        /* ads7846_rx_val() did in-place conversion (including byteswap) from
         * on-the-wire format as part of debouncing to get stable readings.
         */
-       x = packet->tc.x;
-       y = packet->tc.y;
-       z1 = packet->tc.z1;
-       z2 = packet->tc.z2;
+       if (ts->model == 7845) {
+               x = *(u16 *)packet->tc.x_buf;
+               y = *(u16 *)packet->tc.y_buf;
+               z1 = 0;
+               z2 = 0;
+       } else {
+               x = packet->tc.x;
+               y = packet->tc.y;
+               z1 = packet->tc.z1;
+               z2 = packet->tc.z2;
+       }
 
        /* range filtering */
        if (x == MAX_12BIT)
@@ -551,6 +605,12 @@ static void ads7846_rx(void *ads)
 
        if (ts->model == 7843) {
                Rt = ts->pressure_max / 2;
+       } else if (ts->model == 7845) {
+               if (get_pendown_state(ts))
+                       Rt = ts->pressure_max / 2;
+               else
+                       Rt = 0;
+               dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
        } else if (likely(x && z1)) {
                /* compute touch pressure resistance using equation #2 */
                Rt = z2;
@@ -671,10 +731,14 @@ static void ads7846_rx_val(void *ads)
        m = &ts->msg[ts->msg_idx];
        t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
 
-       /* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
-        * built from two 8 bit values written msb-first.
-        */
-       val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+       if (ts->model == 7845) {
+               val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+       } else {
+               /* adjust:  on-wire is a must-ignore bit, a BE12 value, then
+                * padding; built from two 8 bit values written msb-first.
+                */
+               val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+       }
 
        action = ts->filter(ts->filter_data, ts->msg_idx, &val);
        switch (action) {
@@ -878,14 +942,15 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
 
 static int __devinit ads7846_probe(struct spi_device *spi)
 {
-       struct ads7846                  *ts;
-       struct ads7846_packet           *packet;
-       struct input_dev                *input_dev;
-       struct ads7846_platform_data    *pdata = spi->dev.platform_data;
-       struct spi_message              *m;
-       struct spi_transfer             *x;
-       int                             vref;
-       int                             err;
+       struct ads7846 *ts;
+       struct ads7846_packet *packet;
+       struct input_dev *input_dev;
+       const struct ads7846_platform_data *pdata = spi->dev.platform_data;
+       struct spi_message *m;
+       struct spi_transfer *x;
+       unsigned long irq_flags;
+       int vref;
+       int err;
 
        if (!spi->irq) {
                dev_dbg(&spi->dev, "no IRQ?\n");
@@ -1008,16 +1073,26 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        spi_message_init(m);
 
-       /* y- still on; turn on only y+ (and ADC) */
-       packet->read_y = READ_Y(vref);
-       x->tx_buf = &packet->read_y;
-       x->len = 1;
-       spi_message_add_tail(x, m);
+       if (ts->model == 7845) {
+               packet->read_y_cmd[0] = READ_Y(vref);
+               packet->read_y_cmd[1] = 0;
+               packet->read_y_cmd[2] = 0;
+               x->tx_buf = &packet->read_y_cmd[0];
+               x->rx_buf = &packet->tc.y_buf[0];
+               x->len = 3;
+               spi_message_add_tail(x, m);
+       } else {
+               /* y- still on; turn on only y+ (and ADC) */
+               packet->read_y = READ_Y(vref);
+               x->tx_buf = &packet->read_y;
+               x->len = 1;
+               spi_message_add_tail(x, m);
 
-       x++;
-       x->rx_buf = &packet->tc.y;
-       x->len = 2;
-       spi_message_add_tail(x, m);
+               x++;
+               x->rx_buf = &packet->tc.y;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+       }
 
        /* the first sample after switching drivers can be low quality;
         * optionally discard it, using a second one after the signals
@@ -1043,17 +1118,28 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        m++;
        spi_message_init(m);
 
-       /* turn y- off, x+ on, then leave in lowpower */
-       x++;
-       packet->read_x = READ_X(vref);
-       x->tx_buf = &packet->read_x;
-       x->len = 1;
-       spi_message_add_tail(x, m);
+       if (ts->model == 7845) {
+               x++;
+               packet->read_x_cmd[0] = READ_X(vref);
+               packet->read_x_cmd[1] = 0;
+               packet->read_x_cmd[2] = 0;
+               x->tx_buf = &packet->read_x_cmd[0];
+               x->rx_buf = &packet->tc.x_buf[0];
+               x->len = 3;
+               spi_message_add_tail(x, m);
+       } else {
+               /* turn y- off, x+ on, then leave in lowpower */
+               x++;
+               packet->read_x = READ_X(vref);
+               x->tx_buf = &packet->read_x;
+               x->len = 1;
+               spi_message_add_tail(x, m);
 
-       x++;
-       x->rx_buf = &packet->tc.x;
-       x->len = 2;
-       spi_message_add_tail(x, m);
+               x++;
+               x->rx_buf = &packet->tc.x;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+       }
 
        /* ... maybe discard first sample ... */
        if (pdata->settle_delay_usecs) {
@@ -1144,15 +1230,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        m++;
        spi_message_init(m);
 
-       x++;
-       packet->pwrdown = PWRDOWN;
-       x->tx_buf = &packet->pwrdown;
-       x->len = 1;
-       spi_message_add_tail(x, m);
+       if (ts->model == 7845) {
+               x++;
+               packet->pwrdown_cmd[0] = PWRDOWN;
+               packet->pwrdown_cmd[1] = 0;
+               packet->pwrdown_cmd[2] = 0;
+               x->tx_buf = &packet->pwrdown_cmd[0];
+               x->len = 3;
+       } else {
+               x++;
+               packet->pwrdown = PWRDOWN;
+               x->tx_buf = &packet->pwrdown;
+               x->len = 1;
+               spi_message_add_tail(x, m);
+
+               x++;
+               x->rx_buf = &packet->dummy;
+               x->len = 2;
+       }
 
-       x++;
-       x->rx_buf = &packet->dummy;
-       x->len = 2;
        CS_CHANGE(*x);
        spi_message_add_tail(x, m);
 
@@ -1174,17 +1270,22 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                goto err_put_regulator;
        }
 
-       if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
-                       spi->dev.driver->name, ts)) {
+       irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+
+       err = request_irq(spi->irq, ads7846_irq, irq_flags,
+                         spi->dev.driver->name, ts);
+
+       if (err && !pdata->irq_flags) {
                dev_info(&spi->dev,
                        "trying pin change workaround on irq %d\n", spi->irq);
                err = request_irq(spi->irq, ads7846_irq,
                                  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                                  spi->dev.driver->name, ts);
-               if (err) {
-                       dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
-                       goto err_disable_regulator;
-               }
+       }
+
+       if (err) {
+               dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+               goto err_disable_regulator;
        }
 
        err = ads784x_hwmon_register(spi, ts);
@@ -1196,8 +1297,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        /* take a first sample, leaving nPENIRQ active and vREF off; avoid
         * the touchscreen, in case it's not connected.
         */
-       (void) ads7846_read12_ser(&spi->dev,
-                         READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+       if (ts->model == 7845)
+               ads7845_read12_ser(&spi->dev, PWRDOWN);
+       else
+               (void) ads7846_read12_ser(&spi->dev,
+                               READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
        err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
        if (err)
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644 (file)
index 0000000..4eb7df0
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Driver for cypress touch screen controller
+ *
+ * Copyright (c) 2009 Aava Mobile
+ *
+ * Some cleanups by Alan Cox <alan@linux.intel.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/input/cy8ctmg110_pdata.h>
+
+#define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
+
+/* Touch coordinates */
+#define CY8CTMG110_X_MIN               0
+#define CY8CTMG110_Y_MIN               0
+#define CY8CTMG110_X_MAX               759
+#define CY8CTMG110_Y_MAX               465
+
+
+/* cy8ctmg110 register definitions */
+#define CY8CTMG110_TOUCH_WAKEUP_TIME   0
+#define CY8CTMG110_TOUCH_SLEEP_TIME    2
+#define CY8CTMG110_TOUCH_X1            3
+#define CY8CTMG110_TOUCH_Y1            5
+#define CY8CTMG110_TOUCH_X2            7
+#define CY8CTMG110_TOUCH_Y2            9
+#define CY8CTMG110_FINGERS             11
+#define CY8CTMG110_GESTURE             12
+#define CY8CTMG110_REG_MAX             13
+
+
+/*
+ * The touch driver structure.
+ */
+struct cy8ctmg110 {
+       struct input_dev *input;
+       char phys[32];
+       struct i2c_client *client;
+       int reset_pin;
+       int irq_pin;
+};
+
+/*
+ * cy8ctmg110_power is the routine that is called when touch hardware
+ * will powered off or on.
+ */
+static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
+{
+       if (ts->reset_pin)
+               gpio_direction_output(ts->reset_pin, 1 - poweron);
+}
+
+static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
+               unsigned char len, unsigned char *value)
+{
+       struct i2c_client *client = tsc->client;
+       unsigned int ret;
+       unsigned char i2c_data[6];
+
+       BUG_ON(len > 5);
+
+       i2c_data[0] = reg;
+       memcpy(i2c_data + 1, value, len);
+
+       ret = i2c_master_send(client, i2c_data, len + 1);
+       if (ret != 1) {
+               dev_err(&client->dev, "i2c write data cmd failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
+               unsigned char *data, unsigned char len, unsigned char cmd)
+{
+       struct i2c_client *client = tsc->client;
+       unsigned int ret;
+       struct i2c_msg msg[2] = {
+               /* first write slave position to i2c devices */
+               { client->addr, 0, 1, &cmd },
+               /* Second read data from position */
+               { client->addr, I2C_M_RD, len, data }
+       };
+
+       ret = i2c_transfer(client->adapter, msg, 2);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
+{
+       struct input_dev *input = tsc->input;
+       unsigned char reg_p[CY8CTMG110_REG_MAX];
+       int x, y;
+
+       memset(reg_p, 0, CY8CTMG110_REG_MAX);
+
+       /* Reading coordinates */
+       if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
+               return -EIO;
+
+       y = reg_p[2] << 8 | reg_p[3];
+       x = reg_p[0] << 8 | reg_p[1];
+
+       /* Number of touch */
+       if (reg_p[8] == 0) {
+               input_report_key(input, BTN_TOUCH, 0);
+       } else  {
+               input_report_key(input, BTN_TOUCH, 1);
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+       }
+
+       input_sync(input);
+
+       return 0;
+}
+
+static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
+{
+       unsigned char reg_p[3];
+
+       if (sleep) {
+               reg_p[0] = 0x00;
+               reg_p[1] = 0xff;
+               reg_p[2] = 5;
+       } else {
+               reg_p[0] = 0x10;
+               reg_p[1] = 0xff;
+               reg_p[2] = 0;
+       }
+
+       return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
+}
+
+static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
+{
+       struct cy8ctmg110 *tsc = dev_id;
+
+       cy8ctmg110_touch_pos(tsc);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit cy8ctmg110_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
+       struct cy8ctmg110 *ts;
+       struct input_dev *input_dev;
+       int err;
+
+       /* No pdata no way forward */
+       if (pdata == NULL) {
+               dev_err(&client->dev, "no pdata\n");
+               return -ENODEV;
+       }
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -EIO;
+
+       ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ts || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ts->client = client;
+       ts->input = input_dev;
+
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input0", dev_name(&client->dev));
+
+       input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
+       input_dev->phys = ts->phys;
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+       input_set_abs_params(input_dev, ABS_X,
+                       CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                       CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+
+       if (ts->reset_pin) {
+               err = gpio_request(ts->reset_pin, NULL);
+               if (err) {
+                       dev_err(&client->dev,
+                               "Unable to request GPIO pin %d.\n",
+                               ts->reset_pin);
+                       goto err_free_mem;
+               }
+       }
+
+       cy8ctmg110_power(ts, true);
+       cy8ctmg110_set_sleepmode(ts, false);
+
+       err = gpio_request(ts->irq_pin, "touch_irq_key");
+       if (err < 0) {
+               dev_err(&client->dev,
+                       "Failed to request GPIO %d, error %d\n",
+                       ts->irq_pin, err);
+               goto err_shutoff_device;
+       }
+
+       err = gpio_direction_input(ts->irq_pin);
+       if (err < 0) {
+               dev_err(&client->dev,
+                       "Failed to configure input direction for GPIO %d, error %d\n",
+                       ts->irq_pin, err);
+               goto err_free_irq_gpio;
+       }
+
+       client->irq = gpio_to_irq(ts->irq_pin);
+       if (client->irq < 0) {
+               err = client->irq;
+               dev_err(&client->dev,
+                       "Unable to get irq number for GPIO %d, error %d\n",
+                       ts->irq_pin, err);
+               goto err_free_irq_gpio;
+       }
+
+       err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
+                                  IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+       if (err < 0) {
+               dev_err(&client->dev,
+                       "irq %d busy? error %d\n", client->irq, err);
+               goto err_free_irq_gpio;
+       }
+
+       err = input_register_device(input_dev);
+       if (err)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, ts);
+       device_init_wakeup(&client->dev, 1);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, ts);
+err_free_irq_gpio:
+       gpio_free(ts->irq_pin);
+err_shutoff_device:
+       cy8ctmg110_set_sleepmode(ts, true);
+       cy8ctmg110_power(ts, false);
+       if (ts->reset_pin)
+               gpio_free(ts->reset_pin);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(ts);
+       return err;
+}
+
+#ifdef CONFIG_PM
+static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+       else {
+               cy8ctmg110_set_sleepmode(ts, true);
+               cy8ctmg110_power(ts, false);
+       }
+       return 0;
+}
+
+static int cy8ctmg110_resume(struct i2c_client *client)
+{
+       struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+       else {
+               cy8ctmg110_power(ts, true);
+               cy8ctmg110_set_sleepmode(ts, false);
+       }
+       return 0;
+}
+#endif
+
+static int __devexit cy8ctmg110_remove(struct i2c_client *client)
+{
+       struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+       cy8ctmg110_set_sleepmode(ts, true);
+       cy8ctmg110_power(ts, false);
+
+       free_irq(client->irq, ts);
+       input_unregister_device(ts->input);
+       gpio_free(ts->irq_pin);
+       if (ts->reset_pin)
+               gpio_free(ts->reset_pin);
+       kfree(ts);
+
+       return 0;
+}
+
+static struct i2c_device_id cy8ctmg110_idtable[] = {
+       { CY8CTMG110_DRIVER_NAME, 1 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
+
+static struct i2c_driver cy8ctmg110_driver = {
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = CY8CTMG110_DRIVER_NAME,
+       },
+       .id_table       = cy8ctmg110_idtable,
+       .probe          = cy8ctmg110_probe,
+       .remove         = __devexit_p(cy8ctmg110_remove),
+#ifdef CONFIG_PM
+       .suspend        = cy8ctmg110_suspend,
+       .resume         = cy8ctmg110_resume,
+#endif
+};
+
+static int __init cy8ctmg110_init(void)
+{
+       return i2c_add_driver(&cy8ctmg110_driver);
+}
+
+static void __exit cy8ctmg110_exit(void)
+{
+       i2c_del_driver(&cy8ctmg110_driver);
+}
+
+module_init(cy8ctmg110_init);
+module_exit(cy8ctmg110_exit);
+
+MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
+MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
index 1fb0c2f06a4470657b1b05e5295b77b3c67d6236..6ee9940aaf5b371bf41370aaf571d2e6956de909 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/i2c/mcs5000_ts.h>
+#include <linux/i2c/mcs.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/irq.h>
@@ -105,7 +105,7 @@ enum mcs5000_ts_read_offset {
 struct mcs5000_ts_data {
        struct i2c_client *client;
        struct input_dev *input_dev;
-       const struct mcs5000_ts_platform_data *platform_data;
+       const struct mcs_platform_data *platform_data;
 };
 
 static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
@@ -164,7 +164,7 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
 
 static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
 {
-       const struct mcs5000_ts_platform_data *platform_data =
+       const struct mcs_platform_data *platform_data =
                data->platform_data;
        struct i2c_client *client = data->client;
 
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
new file mode 100644 (file)
index 0000000..66b26ad
--- /dev/null
@@ -0,0 +1,1401 @@
+/*
+ * 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_data),
+                                    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 i2c_client *client, pm_message_t mesg)
+{
+       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 i2c_client *client)
+{
+       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;
+}
+#else
+#define qt602240_suspend       NULL
+#define qt602240_resume                NULL
+#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,
+       },
+       .probe          = qt602240_probe,
+       .remove         = __devexit_p(qt602240_remove),
+       .suspend        = qt602240_suspend,
+       .resume         = qt602240_resume,
+       .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");
index 5b70a1419b4d6da36fe5486b5b732d647691bdff..a644d18c04dce09862663004217864698948fef0 100644 (file)
@@ -355,9 +355,6 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
        struct tps6507x_ts *tsc = tps6507x_dev->ts;
        struct input_dev *input_dev = tsc->input_dev;
 
-       if (!tsc)
-               return 0;
-
        cancel_delayed_work_sync(&tsc->work);
        destroy_workqueue(tsc->wq);
 
index 567d57215c28e14bbe78621d1add3b2d1204ff2f..f45f80f6d3369b03f8b6e1e6a8bcebc827cf3377 100644 (file)
@@ -95,6 +95,7 @@ struct usbtouch_device_info {
        int  (*get_pkt_len) (unsigned char *pkt, int len);
 
        int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
+       int  (*alloc)       (struct usbtouch_usb *usbtouch);
        int  (*init)        (struct usbtouch_usb *usbtouch);
        void (*exit)        (struct usbtouch_usb *usbtouch);
 };
@@ -135,7 +136,7 @@ enum {
        DEVTYPE_JASTEC,
        DEVTYPE_E2I,
        DEVTYPE_ZYTRONIC,
-       DEVTYPE_TC5UH,
+       DEVTYPE_TC45USB,
        DEVTYPE_NEXIO,
 };
 
@@ -222,8 +223,11 @@ static const struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
 #endif
 
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-       {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+       /* TC5UH */
+       {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
+       /* TC4UM */
+       {USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
 #endif
 
 #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
@@ -507,7 +511,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
        int ret = -ENOMEM;
        unsigned char *buf;
 
-       buf = kmalloc(2, GFP_KERNEL);
+       buf = kmalloc(2, GFP_NOIO);
        if (!buf)
                goto err_nobuf;
        /* reset */
@@ -574,10 +578,10 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 #endif
 
 /*****************************************************************************
- * ET&T TC5UH part
+ * ET&T TC5UH/TC4UM part
  */
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
        dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
        dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
@@ -732,11 +736,43 @@ static void nexio_ack_complete(struct urb *urb)
 {
 }
 
+static int nexio_alloc(struct usbtouch_usb *usbtouch)
+{
+       struct nexio_priv *priv;
+       int ret = -ENOMEM;
+
+       usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+       if (!usbtouch->priv)
+               goto out_buf;
+
+       priv = usbtouch->priv;
+
+       priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
+                               GFP_KERNEL);
+       if (!priv->ack_buf)
+               goto err_priv;
+
+       priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+       if (!priv->ack) {
+               dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+               goto err_ack_buf;
+       }
+
+       return 0;
+
+err_ack_buf:
+       kfree(priv->ack_buf);
+err_priv:
+       kfree(priv);
+out_buf:
+       return ret;
+}
+
 static int nexio_init(struct usbtouch_usb *usbtouch)
 {
        struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
        struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
-       struct nexio_priv *priv;
+       struct nexio_priv *priv = usbtouch->priv;
        int ret = -ENOMEM;
        int actual_len, i;
        unsigned char *buf;
@@ -755,7 +791,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
        if (!input_ep || !output_ep)
                return -ENXIO;
 
-       buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
+       buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
        if (!buf)
                goto out_buf;
 
@@ -787,11 +823,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
                switch (buf[0]) {
                case 0x83:      /* firmware version */
                        if (!firmware_ver)
-                               firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
+                               firmware_ver = kstrdup(&buf[2], GFP_NOIO);
                        break;
                case 0x84:      /* device name */
                        if (!device_name)
-                               device_name = kstrdup(&buf[2], GFP_KERNEL);
+                               device_name = kstrdup(&buf[2], GFP_NOIO);
                        break;
                }
        }
@@ -802,36 +838,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
        kfree(firmware_ver);
        kfree(device_name);
 
-       /* prepare ACK URB */
-       ret = -ENOMEM;
-
-       usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
-       if (!usbtouch->priv)
-               goto out_buf;
-
-       priv = usbtouch->priv;
-
-       priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
-                               GFP_KERNEL);
-       if (!priv->ack_buf)
-               goto err_priv;
-
-       priv->ack = usb_alloc_urb(0, GFP_KERNEL);
-       if (!priv->ack) {
-               dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
-               goto err_ack_buf;
-       }
-
        usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
                          priv->ack_buf, sizeof(nexio_ack_pkt),
                          nexio_ack_complete, usbtouch);
        ret = 0;
-       goto out_buf;
 
-err_ack_buf:
-       kfree(priv->ack_buf);
-err_priv:
-       kfree(priv);
 out_buf:
        kfree(buf);
        return ret;
@@ -849,29 +860,32 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
 
 static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
 {
-       int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
        struct nexio_touch_packet *packet = (void *) pkt;
        struct nexio_priv *priv = usbtouch->priv;
+       unsigned int data_len = be16_to_cpu(packet->data_len);
+       unsigned int x_len = be16_to_cpu(packet->x_len);
+       unsigned int y_len = be16_to_cpu(packet->y_len);
+       int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
 
        /* got touch data? */
        if ((pkt[0] & 0xe0) != 0xe0)
                return 0;
 
-       if (be16_to_cpu(packet->data_len) > 0xff)
-               packet->data_len = cpu_to_be16(be16_to_cpu(packet->data_len) - 0x100);
-       if (be16_to_cpu(packet->x_len) > 0xff)
-               packet->x_len = cpu_to_be16(be16_to_cpu(packet->x_len) - 0x80);
+       if (data_len > 0xff)
+               data_len -= 0x100;
+       if (x_len > 0xff)
+               x_len -= 0x80;
 
        /* send ACK */
        ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
 
        if (!usbtouch->type->max_xc) {
-               usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
-               input_set_abs_params(usbtouch->input, ABS_X, 0,
-                                    2 * be16_to_cpu(packet->x_len), 0, 0);
-               usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
-               input_set_abs_params(usbtouch->input, ABS_Y, 0,
-                                    2 * be16_to_cpu(packet->y_len), 0, 0);
+               usbtouch->type->max_xc = 2 * x_len;
+               input_set_abs_params(usbtouch->input, ABS_X,
+                                    0, usbtouch->type->max_xc, 0, 0);
+               usbtouch->type->max_yc = 2 * y_len;
+               input_set_abs_params(usbtouch->input, ABS_Y,
+                                    0, usbtouch->type->max_yc, 0, 0);
        }
        /*
         * The device reports state of IR sensors on X and Y axes.
@@ -881,22 +895,21 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
         * it's disabled (and untested) here as there's no X driver for that.
         */
        begin_x = end_x = begin_y = end_y = -1;
-       for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
+       for (x = 0; x < x_len; x++) {
                if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
                        begin_x = x;
                        continue;
                }
                if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
                        end_x = x - 1;
-                       for (y = be16_to_cpu(packet->x_len);
-                            y < be16_to_cpu(packet->data_len); y++) {
+                       for (y = x_len; y < data_len; y++) {
                                if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
-                                       begin_y = y - be16_to_cpu(packet->x_len);
+                                       begin_y = y - x_len;
                                        continue;
                                }
                                if (end_y == -1 &&
                                    begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
-                                       end_y = y - 1 - be16_to_cpu(packet->x_len);
+                                       end_y = y - 1 - x_len;
                                        w = end_x - begin_x;
                                        h = end_y - begin_y;
 #if 0
@@ -1104,14 +1117,14 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
        },
 #endif
 
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-       [DEVTYPE_TC5UH] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+       [DEVTYPE_TC45USB] = {
                .min_xc         = 0x0,
                .max_xc         = 0x0fff,
                .min_yc         = 0x0,
                .max_yc         = 0x0fff,
                .rept_size      = 5,
-               .read_data      = tc5uh_read_data,
+               .read_data      = tc45usb_read_data,
        },
 #endif
 
@@ -1120,6 +1133,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .rept_size      = 1024,
                .irq_always     = true,
                .read_data      = nexio_read_data,
+               .alloc          = nexio_alloc,
                .init           = nexio_init,
                .exit           = nexio_exit,
        },
@@ -1263,6 +1277,7 @@ static void usbtouch_irq(struct urb *urb)
        usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
 
 exit:
+       usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
                err("%s - usb_submit_urb failed with result: %d",
@@ -1272,25 +1287,89 @@ exit:
 static int usbtouch_open(struct input_dev *input)
 {
        struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+       int r;
 
        usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
 
+       r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
+       if (r < 0)
+               goto out;
+
        if (!usbtouch->type->irq_always) {
-               if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
-                 return -EIO;
+               if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
+                       r = -EIO;
+                       goto out_put;
+               }
        }
 
-       return 0;
+       usbtouch->interface->needs_remote_wakeup = 1;
+out_put:
+       usb_autopm_put_interface(usbtouch->interface);
+out:
+       return r;
 }
 
 static void usbtouch_close(struct input_dev *input)
 {
        struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+       int r;
 
        if (!usbtouch->type->irq_always)
                usb_kill_urb(usbtouch->irq);
+       r = usb_autopm_get_interface(usbtouch->interface);
+       usbtouch->interface->needs_remote_wakeup = 0;
+       if (!r)
+               usb_autopm_put_interface(usbtouch->interface);
 }
 
+static int usbtouch_suspend
+(struct usb_interface *intf, pm_message_t message)
+{
+       struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+       usb_kill_urb(usbtouch->irq);
+
+       return 0;
+}
+
+static int usbtouch_resume(struct usb_interface *intf)
+{
+       struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+       struct input_dev *input = usbtouch->input;
+       int result = 0;
+
+       mutex_lock(&input->mutex);
+       if (input->users || usbtouch->type->irq_always)
+               result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+       mutex_unlock(&input->mutex);
+
+       return result;
+}
+
+static int usbtouch_reset_resume(struct usb_interface *intf)
+{
+       struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+       struct input_dev *input = usbtouch->input;
+       int err = 0;
+
+       /* reinit the device */
+       if (usbtouch->type->init) {
+               err = usbtouch->type->init(usbtouch);
+               if (err) {
+                       dbg("%s - type->init() failed, err: %d",
+                           __func__, err);
+                       return err;
+               }
+       }
+
+       /* restart IO if needed */
+       mutex_lock(&input->mutex);
+       if (input->users)
+               err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+       mutex_unlock(&input->mutex);
+
+       return err;
+}
 
 static void usbtouch_free_buffers(struct usb_device *udev,
                                  struct usbtouch_usb *usbtouch)
@@ -1411,12 +1490,21 @@ static int usbtouch_probe(struct usb_interface *intf,
        usbtouch->irq->transfer_dma = usbtouch->data_dma;
        usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       /* device specific init */
+       /* device specific allocations */
+       if (type->alloc) {
+               err = type->alloc(usbtouch);
+               if (err) {
+                       dbg("%s - type->alloc() failed, err: %d", __func__, err);
+                       goto out_free_urb;
+               }
+       }
+
+       /* device specific initialisation*/
        if (type->init) {
                err = type->init(usbtouch);
                if (err) {
                        dbg("%s - type->init() failed, err: %d", __func__, err);
-                       goto out_free_urb;
+                       goto out_do_exit;
                }
        }
 
@@ -1429,8 +1517,11 @@ static int usbtouch_probe(struct usb_interface *intf,
        usb_set_intfdata(intf, usbtouch);
 
        if (usbtouch->type->irq_always) {
+               /* this can't fail */
+               usb_autopm_get_interface(intf);
                err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
                if (err) {
+                       usb_autopm_put_interface(intf);
                        err("%s - usb_submit_urb failed with result: %d",
                            __func__, err);
                        goto out_unregister_input;
@@ -1481,7 +1572,11 @@ static struct usb_driver usbtouch_driver = {
        .name           = "usbtouchscreen",
        .probe          = usbtouch_probe,
        .disconnect     = usbtouch_disconnect,
+       .suspend        = usbtouch_suspend,
+       .resume         = usbtouch_resume,
+       .reset_resume   = usbtouch_reset_resume,
        .id_table       = usbtouch_devices,
+       .supports_autosuspend = 1,
 };
 
 static int __init usbtouch_init(void)
index 81bf25e67ce1668b88a6af271c994dde5e25cbe5..e4112622e5a25e7eb90b615bcc93475bcfd054a7 100644 (file)
@@ -302,6 +302,15 @@ config LEDS_MC13783
          This option enable support for on-chip LED drivers found
          on Freescale Semiconductor MC13783 PMIC.
 
+config LEDS_NS2
+       tristate "LED support for Network Space v2 GPIO LEDs"
+       depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2
+       default y
+       help
+         This option enable support for the dual-GPIO LED found on the
+         Network Space v2 board (and parents). This include Internet Space v2,
+         Network Space (Max) v2 and d2 Network v2 boards.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        help
index 2493de4993741d8f59b006292e75c97d245baf9a..7d6b95831f8eb5da86fad02ab6eedf680c437e3c 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_LEDS_LT3593)             += leds-lt3593.o
 obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
 obj-$(CONFIG_LEDS_DELL_NETBOOKS)       += dell-led.o
 obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
+obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
new file mode 100644 (file)
index 0000000..74dce4b
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * leds-ns2.c - Driver for the Network Space v2 (and parents) dual-GPIO LED
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.com>
+ *
+ * Based on leds-gpio.c by Raphael Assenat <raph@8d.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/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <mach/leds-ns2.h>
+
+/*
+ * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in
+ * relation with the SATA activity. This capability is exposed through the
+ * "sata" sysfs attribute.
+ *
+ * The following array detail the different LED registers and the combination
+ * of their possible values:
+ *
+ *  cmd_led   |  slow_led  | /SATA active | LED state
+ *            |            |              |
+ *     1      |     0      |      x       |  off
+ *     -      |     1      |      x       |  on
+ *     0      |     0      |      1       |  on
+ *     0      |     0      |      0       |  blink (rate 300ms)
+ */
+
+enum ns2_led_modes {
+       NS_V2_LED_OFF,
+       NS_V2_LED_ON,
+       NS_V2_LED_SATA,
+};
+
+struct ns2_led_mode_value {
+       enum ns2_led_modes      mode;
+       int                     cmd_level;
+       int                     slow_level;
+};
+
+static struct ns2_led_mode_value ns2_led_modval[] = {
+       { NS_V2_LED_OFF , 1, 0 },
+       { NS_V2_LED_ON  , 0, 1 },
+       { NS_V2_LED_ON  , 1, 1 },
+       { NS_V2_LED_SATA, 0, 0 },
+};
+
+struct ns2_led_data {
+       struct led_classdev     cdev;
+       unsigned                cmd;
+       unsigned                slow;
+       unsigned char           sata; /* True when SATA mode active. */
+       rwlock_t                rw_lock; /* Lock GPIOs. */
+};
+
+static int ns2_led_get_mode(struct ns2_led_data *led_dat,
+                           enum ns2_led_modes *mode)
+{
+       int i;
+       int ret = -EINVAL;
+       int cmd_level;
+       int slow_level;
+
+       read_lock(&led_dat->rw_lock);
+
+       cmd_level = gpio_get_value(led_dat->cmd);
+       slow_level = gpio_get_value(led_dat->slow);
+
+       for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) {
+               if (cmd_level == ns2_led_modval[i].cmd_level &&
+                   slow_level == ns2_led_modval[i].slow_level) {
+                       *mode = ns2_led_modval[i].mode;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       read_unlock(&led_dat->rw_lock);
+
+       return ret;
+}
+
+static void ns2_led_set_mode(struct ns2_led_data *led_dat,
+                            enum ns2_led_modes mode)
+{
+       int i;
+
+       write_lock(&led_dat->rw_lock);
+
+       for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) {
+               if (mode == ns2_led_modval[i].mode) {
+                       gpio_set_value(led_dat->cmd,
+                                      ns2_led_modval[i].cmd_level);
+                       gpio_set_value(led_dat->slow,
+                                      ns2_led_modval[i].slow_level);
+               }
+       }
+
+       write_unlock(&led_dat->rw_lock);
+}
+
+static void ns2_led_set(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       struct ns2_led_data *led_dat =
+               container_of(led_cdev, struct ns2_led_data, cdev);
+       enum ns2_led_modes mode;
+
+       if (value == LED_OFF)
+               mode = NS_V2_LED_OFF;
+       else if (led_dat->sata)
+               mode = NS_V2_LED_SATA;
+       else
+               mode = NS_V2_LED_ON;
+
+       ns2_led_set_mode(led_dat, mode);
+}
+
+static ssize_t ns2_led_sata_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buff, size_t count)
+{
+       int ret;
+       unsigned long enable;
+       enum ns2_led_modes mode;
+       struct ns2_led_data *led_dat = dev_get_drvdata(dev);
+
+       ret = strict_strtoul(buff, 10, &enable);
+       if (ret < 0)
+               return ret;
+
+       enable = !!enable;
+
+       if (led_dat->sata == enable)
+               return count;
+
+       ret = ns2_led_get_mode(led_dat, &mode);
+       if (ret < 0)
+               return ret;
+
+       if (enable && mode == NS_V2_LED_ON)
+               ns2_led_set_mode(led_dat, NS_V2_LED_SATA);
+       if (!enable && mode == NS_V2_LED_SATA)
+               ns2_led_set_mode(led_dat, NS_V2_LED_ON);
+
+       led_dat->sata = enable;
+
+       return count;
+}
+
+static ssize_t ns2_led_sata_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ns2_led_data *led_dat = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", led_dat->sata);
+}
+
+static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store);
+
+static int __devinit
+create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
+              const struct ns2_led *template)
+{
+       int ret;
+       enum ns2_led_modes mode;
+
+       ret = gpio_request(template->cmd, template->name);
+       if (ret == 0) {
+               ret = gpio_direction_output(template->cmd,
+                                           gpio_get_value(template->cmd));
+               if (ret)
+                       gpio_free(template->cmd);
+       }
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to setup command GPIO\n",
+                       template->name);
+       }
+
+       ret = gpio_request(template->slow, template->name);
+       if (ret == 0) {
+               ret = gpio_direction_output(template->slow,
+                                           gpio_get_value(template->slow));
+               if (ret)
+                       gpio_free(template->slow);
+       }
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n",
+                       template->name);
+               goto err_free_cmd;
+       }
+
+       rwlock_init(&led_dat->rw_lock);
+
+       led_dat->cdev.name = template->name;
+       led_dat->cdev.default_trigger = template->default_trigger;
+       led_dat->cdev.blink_set = NULL;
+       led_dat->cdev.brightness_set = ns2_led_set;
+       led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led_dat->cmd = template->cmd;
+       led_dat->slow = template->slow;
+
+       ret = ns2_led_get_mode(led_dat, &mode);
+       if (ret < 0)
+               goto err_free_slow;
+
+       /* Set LED initial state. */
+       led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
+       led_dat->cdev.brightness =
+               (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
+
+       ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+       if (ret < 0)
+               goto err_free_slow;
+
+       dev_set_drvdata(led_dat->cdev.dev, led_dat);
+       ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
+       if (ret < 0)
+               goto err_free_cdev;
+
+       return 0;
+
+err_free_cdev:
+       led_classdev_unregister(&led_dat->cdev);
+err_free_slow:
+       gpio_free(led_dat->slow);
+err_free_cmd:
+       gpio_free(led_dat->cmd);
+
+       return ret;
+}
+
+static void __devexit delete_ns2_led(struct ns2_led_data *led_dat)
+{
+       device_remove_file(led_dat->cdev.dev, &dev_attr_sata);
+       led_classdev_unregister(&led_dat->cdev);
+       gpio_free(led_dat->cmd);
+       gpio_free(led_dat->slow);
+}
+
+static int __devinit ns2_led_probe(struct platform_device *pdev)
+{
+       struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
+       struct ns2_led_data *leds_data;
+       int i;
+       int ret;
+
+       if (!pdata)
+               return -EINVAL;
+
+       leds_data = kzalloc(sizeof(struct ns2_led_data) *
+                           pdata->num_leds, GFP_KERNEL);
+       if (!leds_data)
+               return -ENOMEM;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               ret = create_ns2_led(pdev, &leds_data[i], &pdata->leds[i]);
+               if (ret < 0)
+                       goto err;
+
+       }
+
+       platform_set_drvdata(pdev, leds_data);
+
+       return 0;
+
+err:
+       for (i = i - 1; i >= 0; i--)
+               delete_ns2_led(&leds_data[i]);
+
+       kfree(leds_data);
+
+       return ret;
+}
+
+static int __devexit ns2_led_remove(struct platform_device *pdev)
+{
+       int i;
+       struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
+       struct ns2_led_data *leds_data;
+
+       leds_data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->num_leds; i++)
+               delete_ns2_led(&leds_data[i]);
+
+       kfree(leds_data);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ns2_led_driver = {
+       .probe          = ns2_led_probe,
+       .remove         = __devexit_p(ns2_led_remove),
+       .driver         = {
+               .name   = "leds-ns2",
+               .owner  = THIS_MODULE,
+       },
+};
+MODULE_ALIAS("platform:leds-ns2");
+
+static int __init ns2_led_init(void)
+{
+       return platform_driver_register(&ns2_led_driver);
+}
+
+static void __exit ns2_led_exit(void)
+{
+       platform_driver_unregister(&ns2_led_driver);
+}
+
+module_init(ns2_led_init);
+module_exit(ns2_led_exit);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("Network Space v2 LED driver");
+MODULE_LICENSE("GPL");
index d22a8ec523fc1df4f1b7bc57c7e10c378e0f9956..999a8250b3cee372d82e0409621a54ea00da85fe 100644 (file)
@@ -8,6 +8,17 @@ config VIDEO_IR
        depends on IR_CORE
        default IR_CORE
 
+config LIRC
+       tristate
+       default y
+
+       ---help---
+          Enable this option to build the Linux Infrared Remote
+          Control (LIRC) core device interface driver. The LIRC
+          interface passes raw IR to and from userspace, where the
+          LIRC daemon handles protocol decoding for IR reception ann
+          encoding for IR transmitting (aka "blasting").
+
 source "drivers/media/IR/keymaps/Kconfig"
 
 config IR_NEC_DECODER
@@ -33,6 +44,7 @@ config IR_RC5_DECODER
 config IR_RC6_DECODER
        tristate "Enable IR raw decoder for the RC6 protocol"
        depends on IR_CORE
+       select BITREVERSE
        default y
 
        ---help---
@@ -42,6 +54,7 @@ config IR_RC6_DECODER
 config IR_JVC_DECODER
        tristate "Enable IR raw decoder for the JVC protocol"
        depends on IR_CORE
+       select BITREVERSE
        default y
 
        ---help---
@@ -57,6 +70,16 @@ config IR_SONY_DECODER
           Enable this option if you have an infrared remote control which
           uses the Sony protocol, and you need software decoding support.
 
+config IR_LIRC_CODEC
+       tristate "Enable IR to LIRC bridge"
+       depends on IR_CORE
+       depends on LIRC
+       default y
+
+       ---help---
+          Enable this option to pass raw IR to and from userspace via
+          the LIRC interface.
+
 config IR_IMON
        tristate "SoundGraph iMON Receiver and Display"
        depends on USB_ARCH_HAS_HCD
@@ -68,3 +91,15 @@ config IR_IMON
 
           To compile this driver as a module, choose M here: the
           module will be called imon.
+
+config IR_MCEUSB
+       tristate "Windows Media Center Ed. eHome Infrared Transceiver"
+       depends on USB_ARCH_HAS_HCD
+       depends on IR_CORE
+       select USB
+       ---help---
+          Say Y here if you want to use a Windows Media Center Edition
+          eHome Infrared Transceiver.
+
+          To compile this driver as a module, choose M here: the
+          module will be called mceusb.
index b998fcced2e44c1df1e2aea1d8700fecf8681ab3..2ae4f3abfdbd0ca73c5eb48739b4767d3032e0ec 100644 (file)
@@ -5,11 +5,14 @@ obj-y += keymaps/
 
 obj-$(CONFIG_IR_CORE) += ir-core.o
 obj-$(CONFIG_VIDEO_IR) += ir-common.o
+obj-$(CONFIG_LIRC) += lirc_dev.o
 obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
 obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
 obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_IR_IMON) += imon.o
+obj-$(CONFIG_IR_MCEUSB) += mceusb.o
index 4bbd45f4284c37b53c1169b95f250a1eaf44d01b..65c125e44e964ebd71ec15d955bd0a67035e7bb9 100644 (file)
@@ -407,7 +407,7 @@ static int display_close(struct inode *inode, struct file *file)
        struct imon_context *ictx = NULL;
        int retval = 0;
 
-       ictx = (struct imon_context *)file->private_data;
+       ictx = file->private_data;
 
        if (!ictx) {
                err("%s: no context for device", __func__);
@@ -812,7 +812,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
        const unsigned char vfd_packet6[] = {
                0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
 
-       ictx = (struct imon_context *)file->private_data;
+       ictx = file->private_data;
        if (!ictx) {
                err("%s: no context for device", __func__);
                return -ENODEV;
@@ -896,7 +896,7 @@ static ssize_t lcd_write(struct file *file, const char *buf,
        int retval = 0;
        struct imon_context *ictx;
 
-       ictx = (struct imon_context *)file->private_data;
+       ictx = file->private_data;
        if (!ictx) {
                err("%s: no context for device", __func__);
                return -ENODEV;
@@ -1943,7 +1943,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
        return ictx;
 
 urb_submit_failed:
-       input_unregister_device(ictx->idev);
+       ir_input_unregister(ictx->idev);
        input_free_device(ictx->idev);
 idev_setup_failed:
 find_endpoint_failed:
@@ -2067,6 +2067,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
                detected_display_type = IMON_DISPLAY_TYPE_VFD;
                break;
        /* iMON LCD, MCE IR */
+       case 0x9e:
        case 0x9f:
                dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
                detected_display_type = IMON_DISPLAY_TYPE_LCD;
@@ -2306,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
        if (ifnum == 0) {
                ictx->dev_present_intf0 = false;
                usb_kill_urb(ictx->rx_urb_intf0);
-               input_unregister_device(ictx->idev);
+               ir_input_unregister(ictx->idev);
                if (ictx->display_supported) {
                        if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
                                usb_deregister_dev(interface, &imon_lcd_class);
index 9a5e65a471a51a23ca104227a121a6aefada1693..babd52061bc3abe011d53500e39b7d35ca7d1663 100644 (file)
 struct ir_raw_handler {
        struct list_head list;
 
+       u64 protocols; /* which are handled by this handler */
        int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
+
+       /* These two should only be used by the lirc decoder */
        int (*raw_register)(struct input_dev *input_dev);
        int (*raw_unregister)(struct input_dev *input_dev);
 };
 
 struct ir_raw_event_ctrl {
+       struct list_head                list;           /* to keep track of raw clients */
        struct work_struct              rx_work;        /* for the rx decoding workqueue */
        struct kfifo                    kfifo;          /* fifo for the pulse/space durations */
        ktime_t                         last_event;     /* when last event occurred */
        enum raw_event_type             last_type;      /* last event type */
        struct input_dev                *input_dev;     /* pointer to the parent input_dev */
+       u64                             enabled_protocols; /* enabled raw protocol decoders */
+
+       /* raw decoder state follows */
+       struct ir_raw_event prev_ev;
+       struct nec_dec {
+               int state;
+               unsigned count;
+               u32 bits;
+       } nec;
+       struct rc5_dec {
+               int state;
+               u32 bits;
+               unsigned count;
+               unsigned wanted_bits;
+       } rc5;
+       struct rc6_dec {
+               int state;
+               u8 header;
+               u32 body;
+               bool toggle;
+               unsigned count;
+               unsigned wanted_bits;
+       } rc6;
+       struct sony_dec {
+               int state;
+               u32 bits;
+               unsigned count;
+       } sony;
+       struct jvc_dec {
+               int state;
+               u16 bits;
+               u16 old_bits;
+               unsigned count;
+               bool first;
+               bool toggle;
+       } jvc;
+       struct lirc_codec {
+               struct ir_input_dev *ir_dev;
+               struct lirc_driver *drv;
+               int lircdata;
+       } lirc;
 };
 
 /* macros for IR decoders */
@@ -74,6 +119,7 @@ void ir_unregister_class(struct input_dev *input_dev);
 /*
  * Routines from ir-raw-event.c to be used internally and by decoders
  */
+u64 ir_raw_get_allowed_protocols(void);
 int ir_raw_event_register(struct input_dev *input_dev);
 void ir_raw_event_unregister(struct input_dev *input_dev);
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
@@ -123,4 +169,12 @@ void ir_raw_init(void);
 #define load_sony_decode()     0
 #endif
 
+/* from ir-lirc-codec.c */
+#ifdef CONFIG_IR_LIRC_CODEC_MODULE
+#define load_lirc_codec()      request_module("ir-lirc-codec")
+#else
+#define load_lirc_codec()      0
+#endif
+
+
 #endif /* _IR_RAW_EVENT */
index 0b804944cbb08a1bef55cc023568ce0138aa7265..8894d8b360486e56595efbf6617a14925c0ea67e 100644 (file)
 #define JVC_TRAILER_PULSE      (1  * JVC_UNIT)
 #define        JVC_TRAILER_SPACE       (35 * JVC_UNIT)
 
-/* Used to register jvc_decoder clients */
-static LIST_HEAD(decoder_list);
-DEFINE_SPINLOCK(decoder_lock);
-
 enum jvc_state {
        STATE_INACTIVE,
        STATE_HEADER_SPACE,
@@ -38,87 +34,6 @@ enum jvc_state {
        STATE_TRAILER_SPACE,
 };
 
-struct decoder_data {
-       struct list_head        list;
-       struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
-
-       /* State machine control */
-       enum jvc_state          state;
-       u16                     jvc_bits;
-       u16                     jvc_old_bits;
-       unsigned                count;
-       bool                    first;
-       bool                    toggle;
-};
-
-
-/**
- * get_decoder_data()  - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-       struct decoder_data *data = NULL;
-
-       spin_lock(&decoder_lock);
-       list_for_each_entry(data, &decoder_list, list) {
-               if (data->ir_dev == ir_dev)
-                       break;
-       }
-       spin_unlock(&decoder_lock);
-       return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "jvc_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_jvc_decode() - Decode one JVC pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -128,14 +43,10 @@ static struct attribute_group decoder_attribute_group = {
  */
 static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-       struct decoder_data *data;
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct jvc_dec *data = &ir_dev->raw->jvc;
 
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return -EINVAL;
-
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -188,9 +99,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
                if (ev.pulse)
                        break;
 
-               data->jvc_bits <<= 1;
+               data->bits <<= 1;
                if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
-                       data->jvc_bits |= 1;
+                       data->bits |= 1;
                        decrease_duration(&ev, JVC_BIT_1_SPACE);
                } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
                        decrease_duration(&ev, JVC_BIT_0_SPACE);
@@ -223,13 +134,13 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 
                if (data->first) {
                        u32 scancode;
-                       scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
-                                  (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
+                       scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
+                                  (bitrev8((data->bits >> 0) & 0xff) << 0);
                        IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
                        ir_keydown(input_dev, scancode, data->toggle);
                        data->first = false;
-                       data->jvc_old_bits = data->jvc_bits;
-               } else if (data->jvc_bits == data->jvc_old_bits) {
+                       data->old_bits = data->bits;
+               } else if (data->bits == data->old_bits) {
                        IR_dprintk(1, "JVC repeat\n");
                        ir_repeat(input_dev);
                } else {
@@ -249,54 +160,9 @@ out:
        return -EINVAL;
 }
 
-static int ir_jvc_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       struct decoder_data *data;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-               return -ENOMEM;
-       }
-
-       data->ir_dev = ir_dev;
-       data->enabled = 1;
-
-       spin_lock(&decoder_lock);
-       list_add_tail(&data->list, &decoder_list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
-static int ir_jvc_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       static struct decoder_data *data;
-
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return 0;
-
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-       spin_lock(&decoder_lock);
-       list_del(&data->list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
 static struct ir_raw_handler jvc_handler = {
+       .protocols      = IR_TYPE_JVC,
        .decode         = ir_jvc_decode,
-       .raw_register   = ir_jvc_register,
-       .raw_unregister = ir_jvc_unregister,
 };
 
 static int __init ir_jvc_decode_init(void)
index 94a8577e72ebd3ba09e264d2abd2213a0ead42c8..15a0f192d4134fe3fad6b17c60aa431defc0f1e2 100644 (file)
@@ -497,8 +497,9 @@ int __ir_input_register(struct input_dev *input_dev,
                                goto out_event;
                }
 
-       IR_dprintk(1, "Registered input device on %s for %s remote.\n",
-                  driver_name, rc_tab->name);
+       IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
+                  driver_name, rc_tab->name,
+                  ir_dev->props->driver_type == RC_DRIVER_IR_RAW ? " in raw mode" : "");
 
        return 0;
 
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
new file mode 100644 (file)
index 0000000..3ba482d
--- /dev/null
@@ -0,0 +1,278 @@
+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+ *
+ * Copyright (C) 2010 by Jarod Wilson <jarod@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 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/sched.h>
+#include <linux/wait.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <media/ir-core.h>
+#include "ir-core-priv.h"
+
+#define LIRCBUF_SIZE 256
+
+/**
+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
+ *                   lircd userspace daemon for decoding.
+ * @input_dev: the struct input_dev descriptor of the device
+ * @duration:  the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the lirc interfaces aren't wired up.
+ */
+static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
+               return 0;
+
+       if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
+               return -EINVAL;
+
+       IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
+                  TO_US(ev.duration), TO_STR(ev.pulse));
+
+       ir_dev->raw->lirc.lircdata += ev.duration / 1000;
+       if (ev.pulse)
+               ir_dev->raw->lirc.lircdata |= PULSE_BIT;
+
+       lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+                         (unsigned char *) &ir_dev->raw->lirc.lircdata);
+       wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
+
+       ir_dev->raw->lirc.lircdata = 0;
+
+       return 0;
+}
+
+static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
+                                  size_t n, loff_t *ppos)
+{
+       struct lirc_codec *lirc;
+       struct ir_input_dev *ir_dev;
+       int *txbuf; /* buffer with values to transmit */
+       int ret = 0, count;
+
+       lirc = lirc_get_pdata(file);
+       if (!lirc)
+               return -EFAULT;
+
+       if (n % sizeof(int))
+               return -EINVAL;
+
+       count = n / sizeof(int);
+       if (count > LIRCBUF_SIZE || count % 2 == 0)
+               return -EINVAL;
+
+       txbuf = memdup_user(buf, n);
+       if (IS_ERR(txbuf))
+               return PTR_ERR(txbuf);
+
+       ir_dev = lirc->ir_dev;
+       if (!ir_dev) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       if (ir_dev->props && ir_dev->props->tx_ir)
+               ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n);
+
+out:
+       kfree(txbuf);
+       return ret;
+}
+
+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       struct lirc_codec *lirc;
+       struct ir_input_dev *ir_dev;
+       int ret = 0;
+       void *drv_data;
+       unsigned long val;
+
+       lirc = lirc_get_pdata(filep);
+       if (!lirc)
+               return -EFAULT;
+
+       ir_dev = lirc->ir_dev;
+       if (!ir_dev || !ir_dev->props || !ir_dev->props->priv)
+               return -EFAULT;
+
+       drv_data = ir_dev->props->priv;
+
+       switch (cmd) {
+       case LIRC_SET_TRANSMITTER_MASK:
+               ret = get_user(val, (unsigned long *)arg);
+               if (ret)
+                       return ret;
+
+               if (ir_dev->props && ir_dev->props->s_tx_mask)
+                       ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
+               else
+                       return -EINVAL;
+               break;
+
+       case LIRC_SET_SEND_CARRIER:
+               ret = get_user(val, (unsigned long *)arg);
+               if (ret)
+                       return ret;
+
+               if (ir_dev->props && ir_dev->props->s_tx_carrier)
+                       ir_dev->props->s_tx_carrier(drv_data, (u32)val);
+               else
+                       return -EINVAL;
+               break;
+
+       case LIRC_GET_SEND_MODE:
+               val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
+               ret = put_user(val, (unsigned long *)arg);
+               break;
+
+       case LIRC_SET_SEND_MODE:
+               ret = get_user(val, (unsigned long *)arg);
+               if (ret)
+                       return ret;
+
+               if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
+                       return -EINVAL;
+               break;
+
+       default:
+               return lirc_dev_fop_ioctl(filep, cmd, arg);
+       }
+
+       return ret;
+}
+
+static int ir_lirc_open(void *data)
+{
+       return 0;
+}
+
+static void ir_lirc_close(void *data)
+{
+       return;
+}
+
+static struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .write          = ir_lirc_transmit_ir,
+       .unlocked_ioctl = ir_lirc_ioctl,
+       .read           = lirc_dev_fop_read,
+       .poll           = lirc_dev_fop_poll,
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+};
+
+static int ir_lirc_register(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct lirc_driver *drv;
+       struct lirc_buffer *rbuf;
+       int rc = -ENOMEM;
+       unsigned long features;
+
+       drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!drv)
+               return rc;
+
+       rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!rbuf)
+               goto rbuf_alloc_failed;
+
+       rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
+       if (rc)
+               goto rbuf_init_failed;
+
+       features = LIRC_CAN_REC_MODE2;
+       if (ir_dev->props->tx_ir) {
+               features |= LIRC_CAN_SEND_PULSE;
+               if (ir_dev->props->s_tx_mask)
+                       features |= LIRC_CAN_SET_TRANSMITTER_MASK;
+               if (ir_dev->props->s_tx_carrier)
+                       features |= LIRC_CAN_SET_SEND_CARRIER;
+       }
+
+       snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
+                ir_dev->driver_name);
+       drv->minor = -1;
+       drv->features = features;
+       drv->data = &ir_dev->raw->lirc;
+       drv->rbuf = rbuf;
+       drv->set_use_inc = &ir_lirc_open;
+       drv->set_use_dec = &ir_lirc_close;
+       drv->code_length = sizeof(struct ir_raw_event) * 8;
+       drv->fops = &lirc_fops;
+       drv->dev = &ir_dev->dev;
+       drv->owner = THIS_MODULE;
+
+       drv->minor = lirc_register_driver(drv);
+       if (drv->minor < 0) {
+               rc = -ENODEV;
+               goto lirc_register_failed;
+       }
+
+       ir_dev->raw->lirc.drv = drv;
+       ir_dev->raw->lirc.ir_dev = ir_dev;
+       ir_dev->raw->lirc.lircdata = PULSE_MASK;
+
+       return 0;
+
+lirc_register_failed:
+rbuf_init_failed:
+       kfree(rbuf);
+rbuf_alloc_failed:
+       kfree(drv);
+
+       return rc;
+}
+
+static int ir_lirc_unregister(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct lirc_codec *lirc = &ir_dev->raw->lirc;
+
+       lirc_unregister_driver(lirc->drv->minor);
+       lirc_buffer_free(lirc->drv->rbuf);
+       kfree(lirc->drv);
+
+       return 0;
+}
+
+static struct ir_raw_handler lirc_handler = {
+       .protocols      = IR_TYPE_LIRC,
+       .decode         = ir_lirc_decode,
+       .raw_register   = ir_lirc_register,
+       .raw_unregister = ir_lirc_unregister,
+};
+
+static int __init ir_lirc_codec_init(void)
+{
+       ir_raw_handler_register(&lirc_handler);
+
+       printk(KERN_INFO "IR LIRC bridge handler initialized\n");
+       return 0;
+}
+
+static void __exit ir_lirc_codec_exit(void)
+{
+       ir_raw_handler_unregister(&lirc_handler);
+}
+
+module_init(ir_lirc_codec_init);
+module_exit(ir_lirc_codec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("LIRC IR handler bridge");
index ba79233112efa526b04f2cfbc65acd4a16f70b00..52e0f378ae3df2b25a329bd1e0da1e3ba22ec834 100644 (file)
 #define        NEC_TRAILER_PULSE       (1  * NEC_UNIT)
 #define        NEC_TRAILER_SPACE       (10 * NEC_UNIT) /* even longer in reality */
 
-/* Used to register nec_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum nec_state {
        STATE_INACTIVE,
        STATE_HEADER_SPACE,
@@ -40,84 +36,6 @@ enum nec_state {
        STATE_TRAILER_SPACE,
 };
 
-struct decoder_data {
-       struct list_head        list;
-       struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
-
-       /* State machine control */
-       enum nec_state          state;
-       u32                     nec_bits;
-       unsigned                count;
-};
-
-
-/**
- * get_decoder_data()  - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-       struct decoder_data *data = NULL;
-
-       spin_lock(&decoder_lock);
-       list_for_each_entry(data, &decoder_list, list) {
-               if (data->ir_dev == ir_dev)
-                       break;
-       }
-       spin_unlock(&decoder_lock);
-       return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "nec_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -127,16 +45,12 @@ static struct attribute_group decoder_attribute_group = {
  */
 static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-       struct decoder_data *data;
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct nec_dec *data = &ir_dev->raw->nec;
        u32 scancode;
        u8 address, not_address, command, not_command;
 
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return -EINVAL;
-
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -191,9 +105,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
                if (ev.pulse)
                        break;
 
-               data->nec_bits <<= 1;
+               data->bits <<= 1;
                if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
-                       data->nec_bits |= 1;
+                       data->bits |= 1;
                else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
                        break;
                data->count++;
@@ -222,14 +136,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
                if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
                        break;
 
-               address     = bitrev8((data->nec_bits >> 24) & 0xff);
-               not_address = bitrev8((data->nec_bits >> 16) & 0xff);
-               command     = bitrev8((data->nec_bits >>  8) & 0xff);
-               not_command = bitrev8((data->nec_bits >>  0) & 0xff);
+               address     = bitrev8((data->bits >> 24) & 0xff);
+               not_address = bitrev8((data->bits >> 16) & 0xff);
+               command     = bitrev8((data->bits >>  8) & 0xff);
+               not_command = bitrev8((data->bits >>  0) & 0xff);
 
                if ((command ^ not_command) != 0xff) {
                        IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
-                                  data->nec_bits);
+                                  data->bits);
                        break;
                }
 
@@ -256,54 +170,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        return -EINVAL;
 }
 
-static int ir_nec_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       struct decoder_data *data;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-               return -ENOMEM;
-       }
-
-       data->ir_dev = ir_dev;
-       data->enabled = 1;
-
-       spin_lock(&decoder_lock);
-       list_add_tail(&data->list, &decoder_list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
-static int ir_nec_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       static struct decoder_data *data;
-
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return 0;
-
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-       spin_lock(&decoder_lock);
-       list_del(&data->list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
 static struct ir_raw_handler nec_handler = {
+       .protocols      = IR_TYPE_NEC,
        .decode         = ir_nec_decode,
-       .raw_register   = ir_nec_register,
-       .raw_unregister = ir_nec_unregister,
 };
 
 static int __init ir_nec_decode_init(void)
index ea68a3f2effa1a973926e873f86e24ee48a7f4ab..6f192ef31db1ae1be0ab78fd28e9b5ec160d442d 100644 (file)
 /* Define the max number of pulse/space transitions to buffer */
 #define MAX_IR_EVENT_SIZE      512
 
+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+static LIST_HEAD(ir_raw_client_list);
+
 /* Used to handle IR raw handler extensions */
-static LIST_HEAD(ir_raw_handler_list);
 static DEFINE_SPINLOCK(ir_raw_handler_lock);
-
-/**
- * RUN_DECODER()       - runs an operation on all IR decoders
- * @ops:       IR raw handler operation to be called
- * @arg:       arguments to be passed to the callback
- *
- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
- * new decode addition/removal while running, by locking ir_raw_handler_lock
- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum
- * of the return codes.
- */
-#define RUN_DECODER(ops, ...) ({                                           \
-       struct ir_raw_handler           *_ir_raw_handler;                   \
-       int _sumrc = 0, _rc;                                                \
-       spin_lock(&ir_raw_handler_lock);                                    \
-       list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) {  \
-               if (_ir_raw_handler->ops) {                                 \
-                       _rc = _ir_raw_handler->ops(__VA_ARGS__);            \
-                       if (_rc < 0)                                        \
-                               break;                                      \
-                       _sumrc += _rc;                                      \
-               }                                                           \
-       }                                                                   \
-       spin_unlock(&ir_raw_handler_lock);                                  \
-       _sumrc;                                                             \
-})
+static LIST_HEAD(ir_raw_handler_list);
+static u64 available_protocols;
 
 #ifdef MODULE
 /* Used to load the decoders */
@@ -58,57 +36,17 @@ static struct work_struct wq_load;
 static void ir_raw_event_work(struct work_struct *work)
 {
        struct ir_raw_event ev;
+       struct ir_raw_handler *handler;
        struct ir_raw_event_ctrl *raw =
                container_of(work, struct ir_raw_event_ctrl, rx_work);
 
-       while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
-               RUN_DECODER(decode, raw->input_dev, ev);
-}
-
-int ir_raw_event_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir = input_get_drvdata(input_dev);
-       int rc;
-
-       ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
-       if (!ir->raw)
-               return -ENOMEM;
-
-       ir->raw->input_dev = input_dev;
-       INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
-
-       rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
-                        GFP_KERNEL);
-       if (rc < 0) {
-               kfree(ir->raw);
-               ir->raw = NULL;
-               return rc;
-       }
-
-       rc = RUN_DECODER(raw_register, input_dev);
-       if (rc < 0) {
-               kfifo_free(&ir->raw->kfifo);
-               kfree(ir->raw);
-               ir->raw = NULL;
-               return rc;
+       while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
+               spin_lock(&ir_raw_handler_lock);
+               list_for_each_entry(handler, &ir_raw_handler_list, list)
+                       handler->decode(raw->input_dev, ev);
+               spin_unlock(&ir_raw_handler_lock);
+               raw->prev_ev = ev;
        }
-
-       return rc;
-}
-
-void ir_raw_event_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
-       if (!ir->raw)
-               return;
-
-       cancel_work_sync(&ir->raw->rx_work);
-       RUN_DECODER(raw_unregister, input_dev);
-
-       kfifo_free(&ir->raw->kfifo);
-       kfree(ir->raw);
-       ir->raw = NULL;
 }
 
 /**
@@ -204,23 +142,103 @@ void ir_raw_event_handle(struct input_dev *input_dev)
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
+/* used internally by the sysfs interface */
+u64
+ir_raw_get_allowed_protocols()
+{
+       u64 protocols;
+       spin_lock(&ir_raw_handler_lock);
+       protocols = available_protocols;
+       spin_unlock(&ir_raw_handler_lock);
+       return protocols;
+}
+
+/*
+ * Used to (un)register raw event clients
+ */
+int ir_raw_event_register(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir = input_get_drvdata(input_dev);
+       int rc;
+       struct ir_raw_handler *handler;
+
+       ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
+       if (!ir->raw)
+               return -ENOMEM;
+
+       ir->raw->input_dev = input_dev;
+       INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
+       ir->raw->enabled_protocols = ~0;
+       rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+                        GFP_KERNEL);
+       if (rc < 0) {
+               kfree(ir->raw);
+               ir->raw = NULL;
+               return rc;
+       }
+
+       spin_lock(&ir_raw_handler_lock);
+       list_add_tail(&ir->raw->list, &ir_raw_client_list);
+       list_for_each_entry(handler, &ir_raw_handler_list, list)
+               if (handler->raw_register)
+                       handler->raw_register(ir->raw->input_dev);
+       spin_unlock(&ir_raw_handler_lock);
+
+       return 0;
+}
+
+void ir_raw_event_unregister(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir = input_get_drvdata(input_dev);
+       struct ir_raw_handler *handler;
+
+       if (!ir->raw)
+               return;
+
+       cancel_work_sync(&ir->raw->rx_work);
+
+       spin_lock(&ir_raw_handler_lock);
+       list_del(&ir->raw->list);
+       list_for_each_entry(handler, &ir_raw_handler_list, list)
+               if (handler->raw_unregister)
+                       handler->raw_unregister(ir->raw->input_dev);
+       spin_unlock(&ir_raw_handler_lock);
+
+       kfifo_free(&ir->raw->kfifo);
+       kfree(ir->raw);
+       ir->raw = NULL;
+}
+
 /*
  * Extension interface - used to register the IR decoders
  */
 
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
 {
+       struct ir_raw_event_ctrl *raw;
+
        spin_lock(&ir_raw_handler_lock);
        list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+       if (ir_raw_handler->raw_register)
+               list_for_each_entry(raw, &ir_raw_client_list, list)
+                       ir_raw_handler->raw_register(raw->input_dev);
+       available_protocols |= ir_raw_handler->protocols;
        spin_unlock(&ir_raw_handler_lock);
+
        return 0;
 }
 EXPORT_SYMBOL(ir_raw_handler_register);
 
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 {
+       struct ir_raw_event_ctrl *raw;
+
        spin_lock(&ir_raw_handler_lock);
        list_del(&ir_raw_handler->list);
+       if (ir_raw_handler->raw_unregister)
+               list_for_each_entry(raw, &ir_raw_client_list, list)
+                       ir_raw_handler->raw_unregister(raw->input_dev);
+       available_protocols &= ~ir_raw_handler->protocols;
        spin_unlock(&ir_raw_handler_lock);
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
@@ -235,6 +253,7 @@ static void init_decoders(struct work_struct *work)
        load_rc6_decode();
        load_jvc_decode();
        load_sony_decode();
+       load_lirc_codec();
 
        /* If needed, we may later add some init code. In this case,
           it is needed to change the CONFIG_MODULE test at ir-core.h
index 23cdb1b1a3bc01679eea78702f778ffb45e15c5e..df4770d978ad835201ec31341d122f3011db9427 100644 (file)
 #define RC5_BIT_END            (1 * RC5_UNIT)
 #define RC5X_SPACE             (4 * RC5_UNIT)
 
-/* Used to register rc5_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum rc5_state {
        STATE_INACTIVE,
        STATE_BIT_START,
@@ -42,87 +38,6 @@ enum rc5_state {
        STATE_FINISHED,
 };
 
-struct decoder_data {
-       struct list_head        list;
-       struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
-
-       /* State machine control */
-       enum rc5_state          state;
-       u32                     rc5_bits;
-       struct ir_raw_event     prev_ev;
-       unsigned                count;
-       unsigned                wanted_bits;
-};
-
-
-/**
- * get_decoder_data()  - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-       struct decoder_data *data = NULL;
-
-       spin_lock(&decoder_lock);
-       list_for_each_entry(data, &decoder_list, list) {
-               if (data->ir_dev == ir_dev)
-                       break;
-       }
-       spin_unlock(&decoder_lock);
-       return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "rc5_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_rc5_decode() - Decode one RC-5 pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -132,17 +47,13 @@ static struct attribute_group decoder_attribute_group = {
  */
 static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-       struct decoder_data *data;
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct rc5_dec *data = &ir_dev->raw->rc5;
        u8 toggle;
        u32 scancode;
 
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return -EINVAL;
-
-       if (!data->enabled)
-               return 0;
+        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
+                return 0;
 
        if (IS_RESET(ev)) {
                data->state = STATE_INACTIVE;
@@ -176,16 +87,15 @@ again:
                if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
                        break;
 
-               data->rc5_bits <<= 1;
+               data->bits <<= 1;
                if (!ev.pulse)
-                       data->rc5_bits |= 1;
+                       data->bits |= 1;
                data->count++;
-               data->prev_ev = ev;
                data->state = STATE_BIT_END;
                return 0;
 
        case STATE_BIT_END:
-               if (!is_transition(&ev, &data->prev_ev))
+               if (!is_transition(&ev, &ir_dev->raw->prev_ev))
                        break;
 
                if (data->count == data->wanted_bits)
@@ -217,11 +127,11 @@ again:
                if (data->wanted_bits == RC5X_NBITS) {
                        /* RC5X */
                        u8 xdata, command, system;
-                       xdata    = (data->rc5_bits & 0x0003F) >> 0;
-                       command  = (data->rc5_bits & 0x00FC0) >> 6;
-                       system   = (data->rc5_bits & 0x1F000) >> 12;
-                       toggle   = (data->rc5_bits & 0x20000) ? 1 : 0;
-                       command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+                       xdata    = (data->bits & 0x0003F) >> 0;
+                       command  = (data->bits & 0x00FC0) >> 6;
+                       system   = (data->bits & 0x1F000) >> 12;
+                       toggle   = (data->bits & 0x20000) ? 1 : 0;
+                       command += (data->bits & 0x01000) ? 0 : 0x40;
                        scancode = system << 16 | command << 8 | xdata;
 
                        IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
@@ -230,10 +140,10 @@ again:
                } else {
                        /* RC5 */
                        u8 command, system;
-                       command  = (data->rc5_bits & 0x0003F) >> 0;
-                       system   = (data->rc5_bits & 0x007C0) >> 6;
-                       toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
-                       command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+                       command  = (data->bits & 0x0003F) >> 0;
+                       system   = (data->bits & 0x007C0) >> 6;
+                       toggle   = (data->bits & 0x00800) ? 1 : 0;
+                       command += (data->bits & 0x01000) ? 0 : 0x40;
                        scancode = system << 8 | command;
 
                        IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
@@ -252,54 +162,9 @@ out:
        return -EINVAL;
 }
 
-static int ir_rc5_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       struct decoder_data *data;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-               return -ENOMEM;
-       }
-
-       data->ir_dev = ir_dev;
-       data->enabled = 1;
-
-       spin_lock(&decoder_lock);
-       list_add_tail(&data->list, &decoder_list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
-static int ir_rc5_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       static struct decoder_data *data;
-
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return 0;
-
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-       spin_lock(&decoder_lock);
-       list_del(&data->list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
 static struct ir_raw_handler rc5_handler = {
+       .protocols      = IR_TYPE_RC5,
        .decode         = ir_rc5_decode,
-       .raw_register   = ir_rc5_register,
-       .raw_unregister = ir_rc5_unregister,
 };
 
 static int __init ir_rc5_decode_init(void)
index 2bf479f4f1bc6c3c42b66d161a48a40d46e4a134..f1624b8279bcce2d581c567cf0840b38ebfc4bc2 100644 (file)
 #define RC6_STARTBIT_MASK      0x08    /* for the header bits */
 #define RC6_6A_MCE_TOGGLE_MASK 0x8000  /* for the body bits */
 
-/* Used to register rc6_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum rc6_mode {
        RC6_MODE_0,
        RC6_MODE_6A,
@@ -58,89 +54,8 @@ enum rc6_state {
        STATE_FINISHED,
 };
 
-struct decoder_data {
-       struct list_head        list;
-       struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
-
-       /* State machine control */
-       enum rc6_state          state;
-       u8                      header;
-       u32                     body;
-       struct ir_raw_event     prev_ev;
-       bool                    toggle;
-       unsigned                count;
-       unsigned                wanted_bits;
-};
-
-
-/**
- * get_decoder_data()  - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-       struct decoder_data *data = NULL;
-
-       spin_lock(&decoder_lock);
-       list_for_each_entry(data, &decoder_list, list) {
-               if (data->ir_dev == ir_dev)
-                       break;
-       }
-       spin_unlock(&decoder_lock);
-       return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
+static enum rc6_mode rc6_mode(struct rc6_dec *data)
 {
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "rc6_decoder",
-       .attrs  = decoder_attributes,
-};
-
-static enum rc6_mode rc6_mode(struct decoder_data *data) {
        switch (data->header & RC6_MODE_MASK) {
        case 0:
                return RC6_MODE_0;
@@ -162,16 +77,12 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) {
  */
 static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-       struct decoder_data *data;
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct rc6_dec *data = &ir_dev->raw->rc6;
        u32 scancode;
        u8 toggle;
 
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return -EINVAL;
-
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -223,12 +134,11 @@ again:
                if (ev.pulse)
                        data->header |= 1;
                data->count++;
-               data->prev_ev = ev;
                data->state = STATE_HEADER_BIT_END;
                return 0;
 
        case STATE_HEADER_BIT_END:
-               if (!is_transition(&ev, &data->prev_ev))
+               if (!is_transition(&ev, &ir_dev->raw->prev_ev))
                        break;
 
                if (data->count == RC6_HEADER_NBITS)
@@ -244,12 +154,11 @@ again:
                        break;
 
                data->toggle = ev.pulse;
-               data->prev_ev = ev;
                data->state = STATE_TOGGLE_END;
                return 0;
 
        case STATE_TOGGLE_END:
-               if (!is_transition(&ev, &data->prev_ev) ||
+               if (!is_transition(&ev, &ir_dev->raw->prev_ev) ||
                    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
                        break;
 
@@ -259,7 +168,6 @@ again:
                }
 
                data->state = STATE_BODY_BIT_START;
-               data->prev_ev = ev;
                decrease_duration(&ev, RC6_TOGGLE_END);
                data->count = 0;
 
@@ -291,13 +199,11 @@ again:
                if (ev.pulse)
                        data->body |= 1;
                data->count++;
-               data->prev_ev = ev;
-
                data->state = STATE_BODY_BIT_END;
                return 0;
 
        case STATE_BODY_BIT_END:
-               if (!is_transition(&ev, &data->prev_ev))
+               if (!is_transition(&ev, &ir_dev->raw->prev_ev))
                        break;
 
                if (data->count == data->wanted_bits)
@@ -348,54 +254,9 @@ out:
        return -EINVAL;
 }
 
-static int ir_rc6_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       struct decoder_data *data;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-               return -ENOMEM;
-       }
-
-       data->ir_dev = ir_dev;
-       data->enabled = 1;
-
-       spin_lock(&decoder_lock);
-       list_add_tail(&data->list, &decoder_list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
-static int ir_rc6_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       static struct decoder_data *data;
-
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return 0;
-
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-       spin_lock(&decoder_lock);
-       list_del(&data->list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
 static struct ir_raw_handler rc6_handler = {
+       .protocols      = IR_TYPE_RC6,
        .decode         = ir_rc6_decode,
-       .raw_register   = ir_rc6_register,
-       .raw_unregister = ir_rc6_unregister,
 };
 
 static int __init ir_rc6_decode_init(void)
index 9f440c5c060d50e9b1cb5b64bce13816705fa890..b9074f07c7a0570293e46eebb8981900da862035 100644 (file)
 #define SONY_BIT_SPACE         (1 * SONY_UNIT)
 #define SONY_TRAILER_SPACE     (10 * SONY_UNIT) /* minimum */
 
-/* Used to register sony_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum sony_state {
        STATE_INACTIVE,
        STATE_HEADER_SPACE,
@@ -35,84 +31,6 @@ enum sony_state {
        STATE_FINISHED,
 };
 
-struct decoder_data {
-       struct list_head        list;
-       struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
-
-       /* State machine control */
-       enum sony_state         state;
-       u32                     sony_bits;
-       unsigned                count;
-};
-
-
-/**
- * get_decoder_data()  - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-       struct decoder_data *data = NULL;
-
-       spin_lock(&decoder_lock);
-       list_for_each_entry(data, &decoder_list, list) {
-               if (data->ir_dev == ir_dev)
-                       break;
-       }
-       spin_unlock(&decoder_lock);
-       return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "sony_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_sony_decode() - Decode one Sony pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -122,16 +40,12 @@ static struct attribute_group decoder_attribute_group = {
  */
 static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-       struct decoder_data *data;
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct sony_dec *data = &ir_dev->raw->sony;
        u32 scancode;
        u8 device, subdevice, function;
 
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return -EINVAL;
-
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -172,9 +86,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
                if (!ev.pulse)
                        break;
 
-               data->sony_bits <<= 1;
+               data->bits <<= 1;
                if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
-                       data->sony_bits |= 1;
+                       data->bits |= 1;
                else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
                        break;
 
@@ -208,19 +122,19 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 
                switch (data->count) {
                case 12:
-                       device    = bitrev8((data->sony_bits <<  3) & 0xF8);
+                       device    = bitrev8((data->bits <<  3) & 0xF8);
                        subdevice = 0;
-                       function  = bitrev8((data->sony_bits >>  4) & 0xFE);
+                       function  = bitrev8((data->bits >>  4) & 0xFE);
                        break;
                case 15:
-                       device    = bitrev8((data->sony_bits >>  0) & 0xFF);
+                       device    = bitrev8((data->bits >>  0) & 0xFF);
                        subdevice = 0;
-                       function  = bitrev8((data->sony_bits >>  7) & 0xFD);
+                       function  = bitrev8((data->bits >>  7) & 0xFD);
                        break;
                case 20:
-                       device    = bitrev8((data->sony_bits >>  5) & 0xF8);
-                       subdevice = bitrev8((data->sony_bits >>  0) & 0xFF);
-                       function  = bitrev8((data->sony_bits >> 12) & 0xFE);
+                       device    = bitrev8((data->bits >>  5) & 0xF8);
+                       subdevice = bitrev8((data->bits >>  0) & 0xFF);
+                       function  = bitrev8((data->bits >> 12) & 0xFE);
                        break;
                default:
                        IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
@@ -241,54 +155,9 @@ out:
        return -EINVAL;
 }
 
-static int ir_sony_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       struct decoder_data *data;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-               return -ENOMEM;
-       }
-
-       data->ir_dev = ir_dev;
-       data->enabled = 1;
-
-       spin_lock(&decoder_lock);
-       list_add_tail(&data->list, &decoder_list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
-static int ir_sony_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       static struct decoder_data *data;
-
-       data = get_decoder_data(ir_dev);
-       if (!data)
-               return 0;
-
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-       spin_lock(&decoder_lock);
-       list_del(&data->list);
-       spin_unlock(&decoder_lock);
-
-       return 0;
-}
-
 static struct ir_raw_handler sony_handler = {
+       .protocols      = IR_TYPE_SONY,
        .decode         = ir_sony_decode,
-       .raw_register   = ir_sony_register,
-       .raw_unregister = ir_sony_unregister,
 };
 
 static int __init ir_sony_decode_init(void)
index 2098dd1488e00647245057653ef6c1decb514026..6273047e915b4b800527bb50f63463adcf83bbc4 100644 (file)
@@ -33,125 +33,172 @@ static struct class ir_input_class = {
        .devnode        = ir_devnode,
 };
 
+static struct {
+       u64     type;
+       char    *name;
+} proto_names[] = {
+       { IR_TYPE_UNKNOWN,      "unknown"       },
+       { IR_TYPE_RC5,          "rc-5"          },
+       { IR_TYPE_NEC,          "nec"           },
+       { IR_TYPE_RC6,          "rc-6"          },
+       { IR_TYPE_JVC,          "jvc"           },
+       { IR_TYPE_SONY,         "sony"          },
+       { IR_TYPE_LIRC,         "lirc"          },
+};
+
+#define PROTO_NONE     "none"
+
 /**
- * show_protocol() - shows the current IR protocol
+ * show_protocols() - shows the current IR protocol(s)
  * @d:         the device descriptor
  * @mattr:     the device attribute struct (unused)
  * @buf:       a pointer to the output buffer
  *
- * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It returns the protocol name, as understood by the driver.
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
+ * It returns the protocol names of supported protocols.
+ * Enabled protocols are printed in brackets.
  */
-static ssize_t show_protocol(struct device *d,
-                            struct device_attribute *mattr, char *buf)
+static ssize_t show_protocols(struct device *d,
+                             struct device_attribute *mattr, char *buf)
 {
-       char *s;
        struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-
-       IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
-
-       /* FIXME: doesn't support multiple protocols at the same time */
-       if (ir_type == IR_TYPE_UNKNOWN)
-               s = "Unknown";
-       else if (ir_type == IR_TYPE_RC5)
-               s = "rc-5";
-       else if (ir_type == IR_TYPE_NEC)
-               s = "nec";
-       else if (ir_type == IR_TYPE_RC6)
-               s = "rc6";
-       else if (ir_type == IR_TYPE_JVC)
-               s = "jvc";
-       else if (ir_type == IR_TYPE_SONY)
-               s = "sony";
-       else
-               s = "other";
+       u64 allowed, enabled;
+       char *tmp = buf;
+       int i;
+
+       if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+               enabled = ir_dev->rc_tab.ir_type;
+               allowed = ir_dev->props->allowed_protos;
+       } else {
+               enabled = ir_dev->raw->enabled_protocols;
+               allowed = ir_raw_get_allowed_protocols();
+       }
+
+       IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
+                  (long long)allowed,
+                  (long long)enabled);
 
-       return sprintf(buf, "%s\n", s);
+       for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+               if (allowed & enabled & proto_names[i].type)
+                       tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
+               else if (allowed & proto_names[i].type)
+                       tmp += sprintf(tmp, "%s ", proto_names[i].name);
+       }
+
+       if (tmp != buf)
+               tmp--;
+       *tmp = '\n';
+       return tmp + 1 - buf;
 }
 
 /**
- * store_protocol() - shows the current IR protocol
+ * store_protocols() - changes the current IR protocol(s)
  * @d:         the device descriptor
  * @mattr:     the device attribute struct (unused)
  * @buf:       a pointer to the input buffer
  * @len:       length of the input buffer
  *
  * This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It changes the IR the protocol name, if the IR type is recognized
- * by the driver.
- * If an unknown protocol name is used, returns -EINVAL.
+ * It is trigged by writing to /sys/class/rc/rc?/protocols.
+ * Writing "+proto" will add a protocol to the list of enabled protocols.
+ * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "proto" will enable only "proto".
+ * Writing "none" will disable all protocols.
+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name
+ * is used, otherwise @len.
  */
-static ssize_t store_protocol(struct device *d,
-                             struct device_attribute *mattr,
-                             const char *data,
-                             size_t len)
+static ssize_t store_protocols(struct device *d,
+                              struct device_attribute *mattr,
+                              const char *data,
+                              size_t len)
 {
        struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       u64 ir_type = 0;
-       int rc = -EINVAL;
+       bool enable, disable;
+       const char *tmp;
+       u64 type;
+       u64 mask;
+       int rc, i, count = 0;
        unsigned long flags;
-       char *buf;
-
-       while ((buf = strsep((char **) &data, " \n")) != NULL) {
-               if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
-                       ir_type |= IR_TYPE_RC5;
-               if (!strcasecmp(buf, "nec"))
-                       ir_type |= IR_TYPE_NEC;
-               if (!strcasecmp(buf, "jvc"))
-                       ir_type |= IR_TYPE_JVC;
-               if (!strcasecmp(buf, "sony"))
-                       ir_type |= IR_TYPE_SONY;
+
+       if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+               type = ir_dev->rc_tab.ir_type;
+       else
+               type = ir_dev->raw->enabled_protocols;
+
+       while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+               if (!*tmp)
+                       break;
+
+               if (*tmp == '+') {
+                       enable = true;
+                       disable = false;
+                       tmp++;
+               } else if (*tmp == '-') {
+                       enable = false;
+                       disable = true;
+                       tmp++;
+               } else {
+                       enable = false;
+                       disable = false;
+               }
+
+               if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
+                       tmp += sizeof(PROTO_NONE);
+                       mask = 0;
+                       count++;
+               } else {
+                       for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+                               if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
+                                       tmp += strlen(proto_names[i].name);
+                                       mask = proto_names[i].type;
+                                       break;
+                               }
+                       }
+                       if (i == ARRAY_SIZE(proto_names)) {
+                               IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+                               return -EINVAL;
+                       }
+                       count++;
+               }
+
+               if (enable)
+                       type |= mask;
+               else if (disable)
+                       type &= ~mask;
+               else
+                       type = mask;
        }
 
-       if (!ir_type) {
-               IR_dprintk(1, "Unknown protocol\n");
+       if (!count) {
+               IR_dprintk(1, "Protocol not specified\n");
                return -EINVAL;
        }
 
-       if (ir_dev->props && ir_dev->props->change_protocol)
+       if (ir_dev->props && ir_dev->props->change_protocol) {
                rc = ir_dev->props->change_protocol(ir_dev->props->priv,
-                                                   ir_type);
-
-       if (rc < 0) {
-               IR_dprintk(1, "Error setting protocol to %lld\n",
-                          (long long)ir_type);
-               return -EINVAL;
+                                                   type);
+               if (rc < 0) {
+                       IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+                                  (long long)type);
+                       return -EINVAL;
+               }
        }
 
-       spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
-       ir_dev->rc_tab.ir_type = ir_type;
-       spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+       if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+               spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
+               ir_dev->rc_tab.ir_type = type;
+               spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+       } else {
+               ir_dev->raw->enabled_protocols = type;
+       }
 
-       IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
-                  (long long)ir_type);
+       IR_dprintk(1, "Current protocol(s): 0x%llx\n",
+                  (long long)type);
 
        return len;
 }
 
-static ssize_t show_supported_protocols(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       char *orgbuf = buf;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-
-       /* FIXME: doesn't support multiple protocols at the same time */
-       if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
-               buf += sprintf(buf, "unknown ");
-       if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
-               buf += sprintf(buf, "rc-5 ");
-       if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
-               buf += sprintf(buf, "nec ");
-       if (buf == orgbuf)
-               buf += sprintf(buf, "other ");
-
-       buf += sprintf(buf - 1, "\n");
-
-       return buf - orgbuf;
-}
-
 #define ADD_HOTPLUG_VAR(fmt, val...)                                   \
        do {                                                            \
                int err = add_uevent_var(env, fmt, val);                \
@@ -159,7 +206,7 @@ static ssize_t show_supported_protocols(struct device *d,
                        return err;                                     \
        } while (0)
 
-static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
        struct ir_input_dev *ir_dev = dev_get_drvdata(device);
 
@@ -174,34 +221,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 /*
  * Static device attribute struct with the sysfs attributes for IR's
  */
-static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
-                  show_protocol, store_protocol);
+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
+                  show_protocols, store_protocols);
 
-static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
-                  show_supported_protocols, NULL);
-
-static struct attribute *ir_hw_dev_attrs[] = {
-       &dev_attr_protocol.attr,
-       &dev_attr_supported_protocols.attr,
+static struct attribute *rc_dev_attrs[] = {
+       &dev_attr_protocols.attr,
        NULL,
 };
 
-static struct attribute_group ir_hw_dev_attr_grp = {
-       .attrs  = ir_hw_dev_attrs,
+static struct attribute_group rc_dev_attr_grp = {
+       .attrs  = rc_dev_attrs,
 };
 
-static const struct attribute_group *ir_hw_dev_attr_groups[] = {
-       &ir_hw_dev_attr_grp,
+static const struct attribute_group *rc_dev_attr_groups[] = {
+       &rc_dev_attr_grp,
        NULL
 };
 
 static struct device_type rc_dev_type = {
-       .groups         = ir_hw_dev_attr_groups,
-       .uevent         = ir_dev_uevent,
-};
-
-static struct device_type ir_raw_dev_type = {
-       .uevent         = ir_dev_uevent,
+       .groups         = rc_dev_attr_groups,
+       .uevent         = rc_dev_uevent,
 };
 
 /**
@@ -221,11 +260,7 @@ int ir_register_class(struct input_dev *input_dev)
        if (unlikely(devno < 0))
                return devno;
 
-       if (ir_dev->props) {
-               if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
-                       ir_dev->dev.type = &rc_dev_type;
-       } else
-               ir_dev->dev.type = &ir_raw_dev_type;
+       ir_dev->dev.type = &rc_dev_type;
 
        ir_dev->dev.class = &ir_input_class;
        ir_dev->dev.parent = input_dev->dev.parent;
index aea649fbcf5a6a929a88dc7979f7840817b155c8..cbee06243b512c6b6c03b032e2d308dc8c115016 100644 (file)
@@ -14,6 +14,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-budget-ci-old.o \
                        rc-cinergy-1400.o \
                        rc-cinergy.o \
+                       rc-dib0700-nec.o \
+                       rc-dib0700-rc5.o \
                        rc-dm1105-nec.o \
                        rc-dntv-live-dvb-t.o \
                        rc-dntv-live-dvbt-pro.o \
@@ -37,6 +39,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-kaiomy.o \
                        rc-kworld-315u.o \
                        rc-kworld-plus-tv-analog.o \
+                       rc-lirc.o \
                        rc-manli.o \
                        rc-msi-tvanywhere.o \
                        rc-msi-tvanywhere-plus.o \
@@ -57,6 +60,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-pv951.o \
                        rc-rc5-hauppauge-new.o \
                        rc-rc5-tv.o \
+                       rc-rc6-mce.o \
                        rc-real-audio-220-32-keys.o \
                        rc-tbs-nec.o \
                        rc-terratec-cinergy-xs.o \
diff --git a/drivers/media/IR/keymaps/rc-dib0700-nec.c b/drivers/media/IR/keymaps/rc-dib0700-nec.c
new file mode 100644 (file)
index 0000000..ae18320
--- /dev/null
@@ -0,0 +1,124 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.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.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode dib0700_nec_table[] = {
+       /* Key codes for the Pixelview SBTVD remote */
+       { 0x8613, KEY_MUTE },
+       { 0x8612, KEY_POWER },
+       { 0x8601, KEY_1 },
+       { 0x8602, KEY_2 },
+       { 0x8603, KEY_3 },
+       { 0x8604, KEY_4 },
+       { 0x8605, KEY_5 },
+       { 0x8606, KEY_6 },
+       { 0x8607, KEY_7 },
+       { 0x8608, KEY_8 },
+       { 0x8609, KEY_9 },
+       { 0x8600, KEY_0 },
+       { 0x860d, KEY_CHANNELUP },
+       { 0x8619, KEY_CHANNELDOWN },
+       { 0x8610, KEY_VOLUMEUP },
+       { 0x860c, KEY_VOLUMEDOWN },
+
+       { 0x860a, KEY_CAMERA },
+       { 0x860b, KEY_ZOOM },
+       { 0x861b, KEY_BACKSPACE },
+       { 0x8615, KEY_ENTER },
+
+       { 0x861d, KEY_UP },
+       { 0x861e, KEY_DOWN },
+       { 0x860e, KEY_LEFT },
+       { 0x860f, KEY_RIGHT },
+
+       { 0x8618, KEY_RECORD },
+       { 0x861a, KEY_STOP },
+
+       /* Key codes for the EvolutePC TVWay+ remote */
+       { 0x7a00, KEY_MENU },
+       { 0x7a01, KEY_RECORD },
+       { 0x7a02, KEY_PLAY },
+       { 0x7a03, KEY_STOP },
+       { 0x7a10, KEY_CHANNELUP },
+       { 0x7a11, KEY_CHANNELDOWN },
+       { 0x7a12, KEY_VOLUMEUP },
+       { 0x7a13, KEY_VOLUMEDOWN },
+       { 0x7a40, KEY_POWER },
+       { 0x7a41, KEY_MUTE },
+
+       /* Key codes for the Elgato EyeTV Diversity silver remote */
+       { 0x4501, KEY_POWER },
+       { 0x4502, KEY_MUTE },
+       { 0x4503, KEY_1 },
+       { 0x4504, KEY_2 },
+       { 0x4505, KEY_3 },
+       { 0x4506, KEY_4 },
+       { 0x4507, KEY_5 },
+       { 0x4508, KEY_6 },
+       { 0x4509, KEY_7 },
+       { 0x450a, KEY_8 },
+       { 0x450b, KEY_9 },
+       { 0x450c, KEY_LAST },
+       { 0x450d, KEY_0 },
+       { 0x450e, KEY_ENTER },
+       { 0x450f, KEY_RED },
+       { 0x4510, KEY_CHANNELUP },
+       { 0x4511, KEY_GREEN },
+       { 0x4512, KEY_VOLUMEDOWN },
+       { 0x4513, KEY_OK },
+       { 0x4514, KEY_VOLUMEUP },
+       { 0x4515, KEY_YELLOW },
+       { 0x4516, KEY_CHANNELDOWN },
+       { 0x4517, KEY_BLUE },
+       { 0x4518, KEY_LEFT }, /* Skip backwards */
+       { 0x4519, KEY_PLAYPAUSE },
+       { 0x451a, KEY_RIGHT }, /* Skip forward */
+       { 0x451b, KEY_REWIND },
+       { 0x451c, KEY_L }, /* Live */
+       { 0x451d, KEY_FASTFORWARD },
+       { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
+       { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
+       { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
+       { 0x4541, KEY_SCREEN }, /*  Full screen toggle, 'Hold' for Teletext */
+       { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
+};
+
+static struct rc_keymap dib0700_nec_map = {
+       .map = {
+               .scan    = dib0700_nec_table,
+               .size    = ARRAY_SIZE(dib0700_nec_table),
+               .ir_type = IR_TYPE_NEC,
+               .name    = RC_MAP_DIB0700_NEC_TABLE,
+       }
+};
+
+static int __init init_rc_map(void)
+{
+       return ir_register_map(&dib0700_nec_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+       ir_unregister_map(&dib0700_nec_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-dib0700-rc5.c b/drivers/media/IR/keymaps/rc-dib0700-rc5.c
new file mode 100644 (file)
index 0000000..4a4797c
--- /dev/null
@@ -0,0 +1,235 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.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.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode dib0700_rc5_table[] = {
+       /* Key codes for the tiny Pinnacle remote*/
+       { 0x0700, KEY_MUTE },
+       { 0x0701, KEY_MENU }, /* Pinnacle logo */
+       { 0x0739, KEY_POWER },
+       { 0x0703, KEY_VOLUMEUP },
+       { 0x0709, KEY_VOLUMEDOWN },
+       { 0x0706, KEY_CHANNELUP },
+       { 0x070c, KEY_CHANNELDOWN },
+       { 0x070f, KEY_1 },
+       { 0x0715, KEY_2 },
+       { 0x0710, KEY_3 },
+       { 0x0718, KEY_4 },
+       { 0x071b, KEY_5 },
+       { 0x071e, KEY_6 },
+       { 0x0711, KEY_7 },
+       { 0x0721, KEY_8 },
+       { 0x0712, KEY_9 },
+       { 0x0727, KEY_0 },
+       { 0x0724, KEY_SCREEN }, /* 'Square' key */
+       { 0x072a, KEY_TEXT },   /* 'T' key */
+       { 0x072d, KEY_REWIND },
+       { 0x0730, KEY_PLAY },
+       { 0x0733, KEY_FASTFORWARD },
+       { 0x0736, KEY_RECORD },
+       { 0x073c, KEY_STOP },
+       { 0x073f, KEY_CANCEL }, /* '?' key */
+
+       /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+       { 0xeb01, KEY_POWER },
+       { 0xeb02, KEY_1 },
+       { 0xeb03, KEY_2 },
+       { 0xeb04, KEY_3 },
+       { 0xeb05, KEY_4 },
+       { 0xeb06, KEY_5 },
+       { 0xeb07, KEY_6 },
+       { 0xeb08, KEY_7 },
+       { 0xeb09, KEY_8 },
+       { 0xeb0a, KEY_9 },
+       { 0xeb0b, KEY_VIDEO },
+       { 0xeb0c, KEY_0 },
+       { 0xeb0d, KEY_REFRESH },
+       { 0xeb0f, KEY_EPG },
+       { 0xeb10, KEY_UP },
+       { 0xeb11, KEY_LEFT },
+       { 0xeb12, KEY_OK },
+       { 0xeb13, KEY_RIGHT },
+       { 0xeb14, KEY_DOWN },
+       { 0xeb16, KEY_INFO },
+       { 0xeb17, KEY_RED },
+       { 0xeb18, KEY_GREEN },
+       { 0xeb19, KEY_YELLOW },
+       { 0xeb1a, KEY_BLUE },
+       { 0xeb1b, KEY_CHANNELUP },
+       { 0xeb1c, KEY_VOLUMEUP },
+       { 0xeb1d, KEY_MUTE },
+       { 0xeb1e, KEY_VOLUMEDOWN },
+       { 0xeb1f, KEY_CHANNELDOWN },
+       { 0xeb40, KEY_PAUSE },
+       { 0xeb41, KEY_HOME },
+       { 0xeb42, KEY_MENU }, /* DVD Menu */
+       { 0xeb43, KEY_SUBTITLE },
+       { 0xeb44, KEY_TEXT }, /* Teletext */
+       { 0xeb45, KEY_DELETE },
+       { 0xeb46, KEY_TV },
+       { 0xeb47, KEY_DVD },
+       { 0xeb48, KEY_STOP },
+       { 0xeb49, KEY_VIDEO },
+       { 0xeb4a, KEY_AUDIO }, /* Music */
+       { 0xeb4b, KEY_SCREEN }, /* Pic */
+       { 0xeb4c, KEY_PLAY },
+       { 0xeb4d, KEY_BACK },
+       { 0xeb4e, KEY_REWIND },
+       { 0xeb4f, KEY_FASTFORWARD },
+       { 0xeb54, KEY_PREVIOUS },
+       { 0xeb58, KEY_RECORD },
+       { 0xeb5c, KEY_NEXT },
+
+       /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+       { 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_KPASTERISK },
+       { 0x1e0b, KEY_RED },
+       { 0x1e0c, KEY_RADIO },
+       { 0x1e0d, KEY_MENU },
+       { 0x1e0e, KEY_GRAVE }, /* # */
+       { 0x1e0f, KEY_MUTE },
+       { 0x1e10, KEY_VOLUMEUP },
+       { 0x1e11, KEY_VOLUMEDOWN },
+       { 0x1e12, KEY_CHANNEL },
+       { 0x1e14, KEY_UP },
+       { 0x1e15, KEY_DOWN },
+       { 0x1e16, KEY_LEFT },
+       { 0x1e17, KEY_RIGHT },
+       { 0x1e18, KEY_VIDEO },
+       { 0x1e19, KEY_AUDIO },
+       { 0x1e1a, KEY_MEDIA },
+       { 0x1e1b, KEY_EPG },
+       { 0x1e1c, KEY_TV },
+       { 0x1e1e, KEY_NEXT },
+       { 0x1e1f, KEY_BACK },
+       { 0x1e20, KEY_CHANNELUP },
+       { 0x1e21, KEY_CHANNELDOWN },
+       { 0x1e24, KEY_LAST }, /* Skip backwards */
+       { 0x1e25, KEY_OK },
+       { 0x1e29, KEY_BLUE},
+       { 0x1e2e, KEY_GREEN },
+       { 0x1e30, KEY_PAUSE },
+       { 0x1e32, KEY_REWIND },
+       { 0x1e34, KEY_FASTFORWARD },
+       { 0x1e35, KEY_PLAY },
+       { 0x1e36, KEY_STOP },
+       { 0x1e37, KEY_RECORD },
+       { 0x1e38, KEY_YELLOW },
+       { 0x1e3b, KEY_GOTO },
+       { 0x1e3d, KEY_POWER },
+
+       /* Key codes for the Leadtek Winfast DTV Dongle */
+       { 0x0042, KEY_POWER },
+       { 0x077c, KEY_TUNER },
+       { 0x0f4e, KEY_PRINT }, /* PREVIEW */
+       { 0x0840, KEY_SCREEN }, /* full screen toggle*/
+       { 0x0f71, KEY_DOT }, /* frequency */
+       { 0x0743, KEY_0 },
+       { 0x0c41, KEY_1 },
+       { 0x0443, KEY_2 },
+       { 0x0b7f, KEY_3 },
+       { 0x0e41, KEY_4 },
+       { 0x0643, KEY_5 },
+       { 0x097f, KEY_6 },
+       { 0x0d7e, KEY_7 },
+       { 0x057c, KEY_8 },
+       { 0x0a40, KEY_9 },
+       { 0x0e4e, KEY_CLEAR },
+       { 0x047c, KEY_CHANNEL }, /* show channel number */
+       { 0x0f41, KEY_LAST }, /* recall */
+       { 0x0342, KEY_MUTE },
+       { 0x064c, KEY_RESERVED }, /* PIP button*/
+       { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
+       { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+       { 0x0b70, KEY_RECORD },
+       { 0x037d, KEY_VOLUMEUP },
+       { 0x017d, KEY_VOLUMEDOWN },
+       { 0x0242, KEY_CHANNELUP },
+       { 0x007d, KEY_CHANNELDOWN },
+
+       /* Key codes for Nova-TD "credit card" remote control. */
+       { 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_CHANNEL },
+       { 0x1d14, KEY_UP },
+       { 0x1d15, KEY_DOWN },
+       { 0x1d16, KEY_LEFT },
+       { 0x1d17, KEY_RIGHT },
+       { 0x1d1c, KEY_TV },
+       { 0x1d1e, KEY_NEXT },
+       { 0x1d1f, KEY_BACK },
+       { 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 },
+};
+
+static struct rc_keymap dib0700_rc5_map = {
+       .map = {
+               .scan    = dib0700_rc5_table,
+               .size    = ARRAY_SIZE(dib0700_rc5_table),
+               .ir_type = IR_TYPE_RC5,
+               .name    = RC_MAP_DIB0700_RC5_TABLE,
+       }
+};
+
+static int __init init_rc_map(void)
+{
+       return ir_register_map(&dib0700_rc5_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+       ir_unregister_map(&dib0700_rc5_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/IR/keymaps/rc-lirc.c
new file mode 100644 (file)
index 0000000..43fcf90
--- /dev/null
@@ -0,0 +1,41 @@
+/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass
+ * all raw IR data to the lirc userspace decoder.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@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/ir-core.h>
+
+static struct ir_scancode lirc[] = {
+       { },
+};
+
+static struct rc_keymap lirc_map = {
+       .map = {
+               .scan    = lirc,
+               .size    = ARRAY_SIZE(lirc),
+               .ir_type = IR_TYPE_LIRC,
+               .name    = RC_MAP_LIRC,
+       }
+};
+
+static int __init init_rc_map_lirc(void)
+{
+       return ir_register_map(&lirc_map);
+}
+
+static void __exit exit_rc_map_lirc(void)
+{
+       ir_unregister_map(&lirc_map);
+}
+
+module_init(init_rc_map_lirc)
+module_exit(exit_rc_map_lirc)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c
new file mode 100644 (file)
index 0000000..c6726a8
--- /dev/null
@@ -0,0 +1,105 @@
+/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use
+ * with the Media Center Edition eHome Infrared Transceiver.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@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>
+
+static struct ir_scancode rc6_mce[] = {
+       { 0x800f0415, KEY_REWIND },
+       { 0x800f0414, KEY_FASTFORWARD },
+       { 0x800f041b, KEY_PREVIOUS },
+       { 0x800f041a, KEY_NEXT },
+
+       { 0x800f0416, KEY_PLAY },
+       { 0x800f0418, KEY_PAUSE },
+       { 0x800f0419, KEY_STOP },
+       { 0x800f0417, KEY_RECORD },
+
+       { 0x800f041e, KEY_UP },
+       { 0x800f041f, KEY_DOWN },
+       { 0x800f0420, KEY_LEFT },
+       { 0x800f0421, KEY_RIGHT },
+
+       { 0x800f040b, KEY_ENTER },
+       { 0x800f0422, KEY_OK },
+       { 0x800f0423, KEY_EXIT },
+       { 0x800f040a, KEY_DELETE },
+
+       { 0x800f040e, KEY_MUTE },
+       { 0x800f0410, KEY_VOLUMEUP },
+       { 0x800f0411, KEY_VOLUMEDOWN },
+       { 0x800f0412, KEY_CHANNELUP },
+       { 0x800f0413, KEY_CHANNELDOWN },
+
+       { 0x800f0401, KEY_NUMERIC_1 },
+       { 0x800f0402, KEY_NUMERIC_2 },
+       { 0x800f0403, KEY_NUMERIC_3 },
+       { 0x800f0404, KEY_NUMERIC_4 },
+       { 0x800f0405, KEY_NUMERIC_5 },
+       { 0x800f0406, KEY_NUMERIC_6 },
+       { 0x800f0407, KEY_NUMERIC_7 },
+       { 0x800f0408, KEY_NUMERIC_8 },
+       { 0x800f0409, KEY_NUMERIC_9 },
+       { 0x800f0400, KEY_NUMERIC_0 },
+
+       { 0x800f041d, KEY_NUMERIC_STAR },
+       { 0x800f041c, KEY_NUMERIC_POUND },
+
+       { 0x800f0446, KEY_TV },
+       { 0x800f0447, KEY_AUDIO }, /* My Music */
+       { 0x800f0448, KEY_PVR }, /* RecordedTV */
+       { 0x800f0449, KEY_CAMERA },
+       { 0x800f044a, KEY_VIDEO },
+       { 0x800f0424, KEY_DVD },
+       { 0x800f0425, KEY_TUNER }, /* LiveTV */
+       { 0x800f0450, KEY_RADIO },
+
+       { 0x800f044c, KEY_LANGUAGE },
+       { 0x800f0427, KEY_ZOOM }, /* Aspect */
+
+       { 0x800f045b, KEY_RED },
+       { 0x800f045c, KEY_GREEN },
+       { 0x800f045d, KEY_YELLOW },
+       { 0x800f045e, KEY_BLUE },
+
+       { 0x800f040f, KEY_INFO },
+       { 0x800f0426, KEY_EPG }, /* Guide */
+       { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
+       { 0x800f044d, KEY_TITLE },
+
+       { 0x800f040c, KEY_POWER },
+       { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+
+};
+
+static struct rc_keymap rc6_mce_map = {
+       .map = {
+               .scan    = rc6_mce,
+               .size    = ARRAY_SIZE(rc6_mce),
+               .ir_type = IR_TYPE_RC6,
+               .name    = RC_MAP_RC6_MCE,
+       }
+};
+
+static int __init init_rc_map_rc6_mce(void)
+{
+       return ir_register_map(&rc6_mce_map);
+}
+
+static void __exit exit_rc_map_rc6_mce(void)
+{
+       ir_unregister_map(&rc6_mce_map);
+}
+
+module_init(init_rc_map_rc6_mce)
+module_exit(exit_rc_map_rc6_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c
new file mode 100644 (file)
index 0000000..899891b
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ *
+ *  This program is free software; 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+static int debug;
+
+#define IRCTL_DEV_NAME "BaseRemoteCtl"
+#define NOPLUG         -1
+#define LOGHEAD                "lirc_dev (%s[%d]): "
+
+static dev_t lirc_base_dev;
+
+struct irctl {
+       struct lirc_driver d;
+       int attached;
+       int open;
+
+       struct mutex irctl_lock;
+       struct lirc_buffer *buf;
+       unsigned int chunk_size;
+
+       struct task_struct *task;
+       long jiffies_to_wait;
+
+       struct cdev cdev;
+};
+
+static DEFINE_MUTEX(lirc_dev_lock);
+
+static struct irctl *irctls[MAX_IRCTL_DEVICES];
+
+/* Only used for sysfs but defined to void otherwise */
+static struct class *lirc_class;
+
+/*  helper function
+ *  initializes the irctl structure
+ */
+static void init_irctl(struct irctl *ir)
+{
+       dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
+               ir->d.name, ir->d.minor);
+       mutex_init(&ir->irctl_lock);
+       ir->d.minor = NOPLUG;
+}
+
+static void cleanup(struct irctl *ir)
+{
+       dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
+
+       device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+
+       if (ir->buf != ir->d.rbuf) {
+               lirc_buffer_free(ir->buf);
+               kfree(ir->buf);
+       }
+       ir->buf = NULL;
+}
+
+/*  helper function
+ *  reads key codes from driver and puts them into buffer
+ *  returns 0 on success
+ */
+static int add_to_buf(struct irctl *ir)
+{
+       if (ir->d.add_to_buf) {
+               int res = -ENODATA;
+               int got_data = 0;
+
+               /*
+                * service the device as long as it is returning
+                * data and we have space
+                */
+get_data:
+               res = ir->d.add_to_buf(ir->d.data, ir->buf);
+               if (res == 0) {
+                       got_data++;
+                       goto get_data;
+               }
+
+               if (res == -ENODEV)
+                       kthread_stop(ir->task);
+
+               return got_data ? 0 : res;
+       }
+
+       return 0;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *irctl)
+{
+       struct irctl *ir = irctl;
+
+       dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n",
+               ir->d.name, ir->d.minor);
+
+       do {
+               if (ir->open) {
+                       if (ir->jiffies_to_wait) {
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               schedule_timeout(ir->jiffies_to_wait);
+                       }
+                       if (kthread_should_stop())
+                               break;
+                       if (!add_to_buf(ir))
+                               wake_up_interruptible(&ir->buf->wait_poll);
+               } else {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule();
+               }
+       } while (!kthread_should_stop());
+
+       dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n",
+               ir->d.name, ir->d.minor);
+
+       return 0;
+}
+
+
+static struct file_operations fops = {
+       .owner          = THIS_MODULE,
+       .read           = lirc_dev_fop_read,
+       .write          = lirc_dev_fop_write,
+       .poll           = lirc_dev_fop_poll,
+       .unlocked_ioctl = lirc_dev_fop_ioctl,
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+};
+
+static int lirc_cdev_add(struct irctl *ir)
+{
+       int retval;
+       struct lirc_driver *d = &ir->d;
+
+       if (d->fops) {
+               cdev_init(&ir->cdev, d->fops);
+               ir->cdev.owner = d->owner;
+       } else {
+               cdev_init(&ir->cdev, &fops);
+               ir->cdev.owner = THIS_MODULE;
+       }
+       kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+
+       retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+       if (retval)
+               kobject_put(&ir->cdev.kobj);
+
+       return retval;
+}
+
+int lirc_register_driver(struct lirc_driver *d)
+{
+       struct irctl *ir;
+       int minor;
+       int bytes_in_key;
+       unsigned int chunk_size;
+       unsigned int buffer_size;
+       int err;
+
+       if (!d) {
+               printk(KERN_ERR "lirc_dev: lirc_register_driver: "
+                      "driver pointer must be not NULL!\n");
+               err = -EBADRQC;
+               goto out;
+       }
+
+       if (MAX_IRCTL_DEVICES <= d->minor) {
+               dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                       "\"minor\" must be between 0 and %d (%d)!\n",
+                       MAX_IRCTL_DEVICES-1, d->minor);
+               err = -EBADRQC;
+               goto out;
+       }
+
+       if (1 > d->code_length || (BUFLEN * 8) < d->code_length) {
+               dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                       "code length in bits for minor (%d) "
+                       "must be less than %d!\n",
+                       d->minor, BUFLEN * 8);
+               err = -EBADRQC;
+               goto out;
+       }
+
+       dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n",
+               d->sample_rate);
+       if (d->sample_rate) {
+               if (2 > d->sample_rate || HZ < d->sample_rate) {
+                       dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                               "sample_rate must be between 2 and %d!\n", HZ);
+                       err = -EBADRQC;
+                       goto out;
+               }
+               if (!d->add_to_buf) {
+                       dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                               "add_to_buf cannot be NULL when "
+                               "sample_rate is set\n");
+                       err = -EBADRQC;
+                       goto out;
+               }
+       } else if (!(d->fops && d->fops->read) && !d->rbuf) {
+               dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                       "fops->read and rbuf cannot all be NULL!\n");
+               err = -EBADRQC;
+               goto out;
+       } else if (!d->rbuf) {
+               if (!(d->fops && d->fops->read && d->fops->poll &&
+                     d->fops->unlocked_ioctl)) {
+                       dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                               "neither read, poll nor unlocked_ioctl can be NULL!\n");
+                       err = -EBADRQC;
+                       goto out;
+               }
+       }
+
+       mutex_lock(&lirc_dev_lock);
+
+       minor = d->minor;
+
+       if (minor < 0) {
+               /* find first free slot for driver */
+               for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
+                       if (!irctls[minor])
+                               break;
+               if (MAX_IRCTL_DEVICES == minor) {
+                       dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                               "no free slots for drivers!\n");
+                       err = -ENOMEM;
+                       goto out_lock;
+               }
+       } else if (irctls[minor]) {
+               dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                       "minor (%d) just registered!\n", minor);
+               err = -EBUSY;
+               goto out_lock;
+       }
+
+       ir = kzalloc(sizeof(struct irctl), GFP_KERNEL);
+       if (!ir) {
+               err = -ENOMEM;
+               goto out_lock;
+       }
+       init_irctl(ir);
+       irctls[minor] = ir;
+       d->minor = minor;
+
+       if (d->sample_rate) {
+               ir->jiffies_to_wait = HZ / d->sample_rate;
+       } else {
+               /* it means - wait for external event in task queue */
+               ir->jiffies_to_wait = 0;
+       }
+
+       /* some safety check 8-) */
+       d->name[sizeof(d->name)-1] = '\0';
+
+       bytes_in_key = BITS_TO_LONGS(d->code_length) +
+                       (d->code_length % 8 ? 1 : 0);
+       buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
+       chunk_size  = d->chunk_size  ? d->chunk_size  : bytes_in_key;
+
+       if (d->rbuf) {
+               ir->buf = d->rbuf;
+       } else {
+               ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+               if (!ir->buf) {
+                       err = -ENOMEM;
+                       goto out_lock;
+               }
+               err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
+               if (err) {
+                       kfree(ir->buf);
+                       goto out_lock;
+               }
+       }
+       ir->chunk_size = ir->buf->chunk_size;
+
+       if (d->features == 0)
+               d->features = LIRC_CAN_REC_LIRCCODE;
+
+       ir->d = *d;
+       ir->d.minor = minor;
+
+       device_create(lirc_class, ir->d.dev,
+                     MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
+                     "lirc%u", ir->d.minor);
+
+       if (d->sample_rate) {
+               /* try to fire up polling thread */
+               ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
+               if (IS_ERR(ir->task)) {
+                       dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+                               "cannot run poll thread for minor = %d\n",
+                               d->minor);
+                       err = -ECHILD;
+                       goto out_sysfs;
+               }
+       }
+
+       err = lirc_cdev_add(ir);
+       if (err)
+               goto out_sysfs;
+
+       ir->attached = 1;
+       mutex_unlock(&lirc_dev_lock);
+
+       dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
+                ir->d.name, ir->d.minor);
+       return minor;
+
+out_sysfs:
+       device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+out_lock:
+       mutex_unlock(&lirc_dev_lock);
+out:
+       return err;
+}
+EXPORT_SYMBOL(lirc_register_driver);
+
+int lirc_unregister_driver(int minor)
+{
+       struct irctl *ir;
+
+       if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
+               printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
+                      "\"minor (%d)\" must be between 0 and %d!\n",
+                      minor, MAX_IRCTL_DEVICES-1);
+               return -EBADRQC;
+       }
+
+       ir = irctls[minor];
+
+       mutex_lock(&lirc_dev_lock);
+
+       if (ir->d.minor != minor) {
+               printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
+                      "minor (%d) device not registered!", minor);
+               mutex_unlock(&lirc_dev_lock);
+               return -ENOENT;
+       }
+
+       /* end up polling thread */
+       if (ir->task)
+               kthread_stop(ir->task);
+
+       dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
+               ir->d.name, ir->d.minor);
+
+       ir->attached = 0;
+       if (ir->open) {
+               dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
+                       ir->d.name, ir->d.minor);
+               wake_up_interruptible(&ir->buf->wait_poll);
+               mutex_lock(&ir->irctl_lock);
+               ir->d.set_use_dec(ir->d.data);
+               module_put(ir->d.owner);
+               mutex_unlock(&ir->irctl_lock);
+               cdev_del(&ir->cdev);
+       } else {
+               cleanup(ir);
+               cdev_del(&ir->cdev);
+               kfree(ir);
+               irctls[minor] = NULL;
+       }
+
+       mutex_unlock(&lirc_dev_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(lirc_unregister_driver);
+
+int lirc_dev_fop_open(struct inode *inode, struct file *file)
+{
+       struct irctl *ir;
+       int retval = 0;
+
+       if (iminor(inode) >= MAX_IRCTL_DEVICES) {
+               printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n",
+                      iminor(inode));
+               return -ENODEV;
+       }
+
+       if (mutex_lock_interruptible(&lirc_dev_lock))
+               return -ERESTARTSYS;
+
+       ir = irctls[iminor(inode)];
+       if (!ir) {
+               retval = -ENODEV;
+               goto error;
+       }
+       file->private_data = ir;
+
+       dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
+
+       if (ir->d.minor == NOPLUG) {
+               retval = -ENODEV;
+               goto error;
+       }
+
+       if (ir->open) {
+               retval = -EBUSY;
+               goto error;
+       }
+
+       if (try_module_get(ir->d.owner)) {
+               ++ir->open;
+               retval = ir->d.set_use_inc(ir->d.data);
+
+               if (retval) {
+                       module_put(ir->d.owner);
+                       --ir->open;
+               } else {
+                       lirc_buffer_clear(ir->buf);
+               }
+               if (ir->task)
+                       wake_up_process(ir->task);
+       }
+
+error:
+       if (ir)
+               dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n",
+                       ir->d.name, ir->d.minor, retval);
+
+       mutex_unlock(&lirc_dev_lock);
+
+       return retval;
+}
+EXPORT_SYMBOL(lirc_dev_fop_open);
+
+int lirc_dev_fop_close(struct inode *inode, struct file *file)
+{
+       struct irctl *ir = irctls[iminor(inode)];
+
+       dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
+
+       WARN_ON(mutex_lock_killable(&lirc_dev_lock));
+
+       --ir->open;
+       if (ir->attached) {
+               ir->d.set_use_dec(ir->d.data);
+               module_put(ir->d.owner);
+       } else {
+               cleanup(ir);
+               irctls[ir->d.minor] = NULL;
+               kfree(ir);
+       }
+
+       mutex_unlock(&lirc_dev_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(lirc_dev_fop_close);
+
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
+{
+       struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+       unsigned int ret;
+
+       dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
+
+       if (!ir->attached) {
+               mutex_unlock(&ir->irctl_lock);
+               return POLLERR;
+       }
+
+       poll_wait(file, &ir->buf->wait_poll, wait);
+
+       if (ir->buf)
+               if (lirc_buffer_empty(ir->buf))
+                       ret = 0;
+               else
+                       ret = POLLIN | POLLRDNORM;
+       else
+               ret = POLLERR;
+
+       dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
+               ir->d.name, ir->d.minor, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(lirc_dev_fop_poll);
+
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       unsigned long mode;
+       int result = 0;
+       struct irctl *ir = file->private_data;
+
+       dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
+               ir->d.name, ir->d.minor, cmd);
+
+       if (ir->d.minor == NOPLUG || !ir->attached) {
+               dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
+                       ir->d.name, ir->d.minor);
+               return -ENODEV;
+       }
+
+       mutex_lock(&ir->irctl_lock);
+
+       switch (cmd) {
+       case LIRC_GET_FEATURES:
+               result = put_user(ir->d.features, (unsigned long *)arg);
+               break;
+       case LIRC_GET_REC_MODE:
+               if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+                       result = -ENOSYS;
+                       break;
+               }
+
+               result = put_user(LIRC_REC2MODE
+                                 (ir->d.features & LIRC_CAN_REC_MASK),
+                                 (unsigned long *)arg);
+               break;
+       case LIRC_SET_REC_MODE:
+               if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+                       result = -ENOSYS;
+                       break;
+               }
+
+               result = get_user(mode, (unsigned long *)arg);
+               if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
+                       result = -EINVAL;
+               /*
+                * FIXME: We should actually set the mode somehow but
+                * for now, lirc_serial doesn't support mode changing either
+                */
+               break;
+       case LIRC_GET_LENGTH:
+               result = put_user(ir->d.code_length, (unsigned long *)arg);
+               break;
+       case LIRC_GET_MIN_TIMEOUT:
+               if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+                   ir->d.min_timeout == 0) {
+                       result = -ENOSYS;
+                       break;
+               }
+
+               result = put_user(ir->d.min_timeout, (unsigned long *)arg);
+               break;
+       case LIRC_GET_MAX_TIMEOUT:
+               if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+                   ir->d.max_timeout == 0) {
+                       result = -ENOSYS;
+                       break;
+               }
+
+               result = put_user(ir->d.max_timeout, (unsigned long *)arg);
+               break;
+       default:
+               result = -EINVAL;
+       }
+
+       dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n",
+               ir->d.name, ir->d.minor, result);
+
+       mutex_unlock(&ir->irctl_lock);
+
+       return result;
+}
+EXPORT_SYMBOL(lirc_dev_fop_ioctl);
+
+ssize_t lirc_dev_fop_read(struct file *file,
+                         char *buffer,
+                         size_t length,
+                         loff_t *ppos)
+{
+       struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+       unsigned char buf[ir->chunk_size];
+       int ret = 0, written = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
+
+       if (mutex_lock_interruptible(&ir->irctl_lock))
+               return -ERESTARTSYS;
+       if (!ir->attached) {
+               mutex_unlock(&ir->irctl_lock);
+               return -ENODEV;
+       }
+
+       if (length % ir->chunk_size) {
+               dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n",
+                       ir->d.name, ir->d.minor);
+               mutex_unlock(&ir->irctl_lock);
+               return -EINVAL;
+       }
+
+       /*
+        * 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(&ir->buf->wait_poll, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       /*
+        * while we didn't provide 'length' bytes, device is opened in blocking
+        * mode and 'copy_to_user' is happy, wait for data.
+        */
+       while (written < length && ret == 0) {
+               if (lirc_buffer_empty(ir->buf)) {
+                       /* According to the read(2) man page, 'written' can be
+                        * returned as less than 'length', instead of blocking
+                        * again, returning -EWOULDBLOCK, or returning
+                        * -ERESTARTSYS */
+                       if (written)
+                               break;
+                       if (file->f_flags & O_NONBLOCK) {
+                               ret = -EWOULDBLOCK;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               ret = -ERESTARTSYS;
+                               break;
+                       }
+
+                       mutex_unlock(&ir->irctl_lock);
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       if (mutex_lock_interruptible(&ir->irctl_lock)) {
+                               ret = -ERESTARTSYS;
+                               remove_wait_queue(&ir->buf->wait_poll, &wait);
+                               set_current_state(TASK_RUNNING);
+                               goto out_unlocked;
+                       }
+
+                       if (!ir->attached) {
+                               ret = -ENODEV;
+                               break;
+                       }
+               } else {
+                       lirc_buffer_read(ir->buf, buf);
+                       ret = copy_to_user((void *)buffer+written, buf,
+                                          ir->buf->chunk_size);
+                       written += ir->buf->chunk_size;
+               }
+       }
+
+       remove_wait_queue(&ir->buf->wait_poll, &wait);
+       set_current_state(TASK_RUNNING);
+       mutex_unlock(&ir->irctl_lock);
+
+out_unlocked:
+       dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
+               ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
+
+       return ret ? ret : written;
+}
+EXPORT_SYMBOL(lirc_dev_fop_read);
+
+void *lirc_get_pdata(struct file *file)
+{
+       void *data = NULL;
+
+       if (file && file->f_dentry && file->f_dentry->d_inode &&
+           file->f_dentry->d_inode->i_rdev) {
+               struct irctl *ir;
+               ir = irctls[iminor(file->f_dentry->d_inode)];
+               data = ir->d.data;
+       }
+
+       return data;
+}
+EXPORT_SYMBOL(lirc_get_pdata);
+
+
+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
+                          size_t length, loff_t *ppos)
+{
+       struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+       dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
+
+       if (!ir->attached)
+               return -ENODEV;
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(lirc_dev_fop_write);
+
+
+static int __init lirc_dev_init(void)
+{
+       int retval;
+
+       lirc_class = class_create(THIS_MODULE, "lirc");
+       if (IS_ERR(lirc_class)) {
+               retval = PTR_ERR(lirc_class);
+               printk(KERN_ERR "lirc_dev: class_create failed\n");
+               goto error;
+       }
+
+       retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
+                                    IRCTL_DEV_NAME);
+       if (retval) {
+               class_destroy(lirc_class);
+               printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n");
+               goto error;
+       }
+
+
+       printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, "
+              "major %d \n", MAJOR(lirc_base_dev));
+
+error:
+       return retval;
+}
+
+
+
+static void __exit lirc_dev_exit(void)
+{
+       class_destroy(lirc_class);
+       unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
+       printk(KERN_INFO "lirc_dev: module unloaded\n");
+}
+
+module_init(lirc_dev_init);
+module_exit(lirc_dev_exit);
+
+MODULE_DESCRIPTION("LIRC base driver module");
+MODULE_AUTHOR("Artur Lipowski");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c
new file mode 100644 (file)
index 0000000..78bf7f7
--- /dev/null
@@ -0,0 +1,1143 @@
+/*
+ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
+ * Conti, Martin Blatter and Daniel Melander, the latter of which was
+ * in turn also based on the lirc_atiusb driver by Paul Miller. The
+ * two mce drivers were merged into one by Jarod Wilson, with transmit
+ * support for the 1st-gen device added primarily by Patrick Calhoun,
+ * with a bit of tweaks by Jarod. Debugging improvements and proper
+ * support for what appears to be 3rd-gen hardware added by Jarod.
+ * Initial port from lirc driver to ir-core drivery by Jarod, based
+ * partially on a port to an earlier proposed IR infrastructure by
+ * Jon Smirl, which included enhancements and simplifications to the
+ * incoming IR buffer parsing routines.
+ *
+ *
+ * This program is free software; 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/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+#include <media/ir-core.h>
+#include <media/ir-common.h>
+
+#define DRIVER_VERSION "1.91"
+#define DRIVER_AUTHOR  "Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_DESC    "Windows Media Center Ed. eHome Infrared Transceiver " \
+                       "device driver"
+#define DRIVER_NAME    "mceusb"
+
+#define USB_BUFLEN     32      /* USB reception buffer length */
+#define USB_CTRL_MSG_SZ        2       /* Size of usb ctrl msg on gen1 hw */
+#define MCE_G1_INIT_MSGS 40    /* Init messages on gen1 hw to throw out */
+
+/* MCE constants */
+#define MCE_CMDBUF_SIZE        384 /* MCE Command buffer length */
+#define MCE_TIME_UNIT  50 /* Approx 50us resolution */
+#define MCE_CODE_LENGTH        5 /* Normal length of packet (with header) */
+#define MCE_PACKET_SIZE        4 /* Normal length of packet (without header) */
+#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_CONTROL_HEADER 0x9F /* MCE status header */
+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
+#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */
+#define MCE_PULSE_BIT  0x80 /* Pulse bit, MSB set == PULSE else SPACE */
+#define MCE_PULSE_MASK 0x7F /* Pulse mask */
+#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */
+#define MCE_PACKET_LENGTH_MASK  0x1F /* Packet length mask */
+
+
+/* module parameters */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* general constants */
+#define SEND_FLAG_IN_PROGRESS  1
+#define SEND_FLAG_COMPLETE     2
+#define RECV_FLAG_IN_PROGRESS  3
+#define RECV_FLAG_COMPLETE     4
+
+#define MCEUSB_RX              1
+#define MCEUSB_TX              2
+
+#define VENDOR_PHILIPS         0x0471
+#define VENDOR_SMK             0x0609
+#define VENDOR_TATUNG          0x1460
+#define VENDOR_GATEWAY         0x107b
+#define VENDOR_SHUTTLE         0x1308
+#define VENDOR_SHUTTLE2                0x051c
+#define VENDOR_MITSUMI         0x03ee
+#define VENDOR_TOPSEED         0x1784
+#define VENDOR_RICAVISION      0x179d
+#define VENDOR_ITRON           0x195d
+#define VENDOR_FIC             0x1509
+#define VENDOR_LG              0x043e
+#define VENDOR_MICROSOFT       0x045e
+#define VENDOR_FORMOSA         0x147a
+#define VENDOR_FINTEK          0x1934
+#define VENDOR_PINNACLE                0x2304
+#define VENDOR_ECS             0x1019
+#define VENDOR_WISTRON         0x0fb8
+#define VENDOR_COMPRO          0x185b
+#define VENDOR_NORTHSTAR       0x04eb
+#define VENDOR_REALTEK         0x0bda
+#define VENDOR_TIVO            0x105a
+
+static struct usb_device_id mceusb_dev_table[] = {
+       /* Original Microsoft MCE IR Transceiver (often HP-branded) */
+       { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+       /* Philips Infrared Transceiver - Sahara branded */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
+       /* Philips Infrared Transceiver - HP branded */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+       /* Philips SRM5100 */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
+       /* Philips Infrared Transceiver - Omaura */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x060f) },
+       /* Philips Infrared Transceiver - Spinel plus */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x0613) },
+       /* Philips eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_PHILIPS, 0x0815) },
+       /* Realtek MCE IR Receiver */
+       { USB_DEVICE(VENDOR_REALTEK, 0x0161) },
+       /* SMK/Toshiba G83C0004D410 */
+       { USB_DEVICE(VENDOR_SMK, 0x031d) },
+       /* SMK eHome Infrared Transceiver (Sony VAIO) */
+       { USB_DEVICE(VENDOR_SMK, 0x0322) },
+       /* bundled with Hauppauge PVR-150 */
+       { USB_DEVICE(VENDOR_SMK, 0x0334) },
+       /* SMK eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_SMK, 0x0338) },
+       /* Tatung eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TATUNG, 0x9150) },
+       /* Shuttle eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) },
+       /* Shuttle eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) },
+       /* Gateway eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_GATEWAY, 0x3009) },
+       /* Mitsumi */
+       { USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
+       /* Topseed eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+       /* Topseed HP eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+       /* Topseed eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+       /* Topseed eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+       /* Topseed eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+       /* Topseed eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+       /* Ricavision internal Infrared Transceiver */
+       { USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
+       /* Itron ione Libra Q-11 */
+       { USB_DEVICE(VENDOR_ITRON, 0x7002) },
+       /* FIC eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_FIC, 0x9242) },
+       /* LG eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_LG, 0x9803) },
+       /* Microsoft MCE Infrared Transceiver */
+       { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) },
+       /* Formosa eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe015) },
+       /* Formosa21 / eHome Infrared Receiver */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
+       /* Formosa aim / Trust MCE Infrared Receiver */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
+       /* Formosa Industrial Computing / Beanbag Emulation Device */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
+       /* Formosa21 / eHome Infrared Receiver */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) },
+       /* Formosa Industrial Computing AIM IR605/A */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
+       /* Formosa Industrial Computing */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+       /* Fintek eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_FINTEK, 0x0602) },
+       /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
+       { USB_DEVICE(VENDOR_FINTEK, 0x0702) },
+       /* Pinnacle Remote Kit */
+       { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+       /* Elitegroup Computer Systems IR */
+       { USB_DEVICE(VENDOR_ECS, 0x0f38) },
+       /* Wistron Corp. eHome Infrared Receiver */
+       { USB_DEVICE(VENDOR_WISTRON, 0x0002) },
+       /* Compro K100 */
+       { USB_DEVICE(VENDOR_COMPRO, 0x3020) },
+       /* Compro K100 v2 */
+       { USB_DEVICE(VENDOR_COMPRO, 0x3082) },
+       /* Northstar Systems, Inc. eHome Infrared Transceiver */
+       { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
+       /* TiVo PC IR Receiver */
+       { USB_DEVICE(VENDOR_TIVO, 0x2000) },
+       /* Terminating entry */
+       { }
+};
+
+static struct usb_device_id gen3_list[] = {
+       { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+       {}
+};
+
+static struct usb_device_id microsoft_gen1_list[] = {
+       { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+       {}
+};
+
+static struct usb_device_id std_tx_mask_list[] = {
+       { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+       { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+       { USB_DEVICE(VENDOR_SMK, 0x031d) },
+       { USB_DEVICE(VENDOR_SMK, 0x0322) },
+       { USB_DEVICE(VENDOR_SMK, 0x0334) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+       { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+       { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+       {}
+};
+
+/* data structure for each usb transceiver */
+struct mceusb_dev {
+       /* ir-core bits */
+       struct ir_input_dev *irdev;
+       struct ir_dev_props *props;
+       struct ir_raw_event rawir;
+
+       /* core device bits */
+       struct device *dev;
+       struct input_dev *idev;
+
+       /* usb */
+       struct usb_device *usbdev;
+       struct urb *urb_in;
+       struct usb_endpoint_descriptor *usb_ep_in;
+       struct usb_endpoint_descriptor *usb_ep_out;
+
+       /* buffers and dma */
+       unsigned char *buf_in;
+       unsigned int len_in;
+       u8 cmd;         /* MCE command type */
+       u8 rem;         /* Remaining IR data bytes in packet */
+       dma_addr_t dma_in;
+       dma_addr_t dma_out;
+
+       struct {
+               u32 connected:1;
+               u32 tx_mask_inverted:1;
+               u32 microsoft_gen1:1;
+               u32 reserved:29;
+       } flags;
+
+       /* transmit support */
+       int send_flags;
+       u32 carrier;
+       unsigned char tx_mask;
+
+       char name[128];
+       char phys[64];
+};
+
+/*
+ * MCE Device Command Strings
+ * Device command responses vary from device to device...
+ * - DEVICE_RESET resets the hardware to its default state
+ * - GET_REVISION fetches the hardware/software revision, common
+ *   replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
+ *   device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
+ *   meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
+ *   ((clk / frequency) - 1)
+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
+ *   response in the form of 9f 0c msb lsb
+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
+ *   the form of 9f 08 bm, where bm is the bitmask
+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
+ *   general use one or short-range learning one, in the form of
+ *   9f 14 ss, where ss is either 01 for long-range or 02 for short
+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency
+ * - SET_TX_BITMASK sets the transmitter bitmask
+ * - SET_RX_TIMEOUT sets the receiver timeout
+ * - SET_RX_SENSOR sets which receiver sensor to use
+ */
+static char DEVICE_RESET[]     = {0x00, 0xff, 0xaa};
+static char GET_REVISION[]     = {0xff, 0x0b};
+static char GET_UNKNOWN[]      = {0xff, 0x18};
+static char GET_UNKNOWN2[]     = {0x9f, 0x05};
+static char GET_CARRIER_FREQ[] = {0x9f, 0x07};
+static char GET_RX_TIMEOUT[]   = {0x9f, 0x0d};
+static char GET_TX_BITMASK[]   = {0x9f, 0x13};
+static char GET_RX_SENSOR[]    = {0x9f, 0x15};
+/* sub in desired values in lower byte or bytes for full command */
+/* FIXME: make use of these for transmit.
+static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00};
+static char SET_TX_BITMASK[]   = {0x9f, 0x08, 0x00};
+static char SET_RX_TIMEOUT[]   = {0x9f, 0x0c, 0x00, 0x00};
+static char SET_RX_SENSOR[]    = {0x9f, 0x14, 0x00};
+*/
+
+static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
+                                int len, bool out)
+{
+       char codes[USB_BUFLEN * 3 + 1];
+       char inout[9];
+       int i;
+       u8 cmd, subcmd, data1, data2;
+       struct device *dev = ir->dev;
+       int idx = 0;
+
+       /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+       if (ir->flags.microsoft_gen1 && !out)
+               idx = 2;
+
+       if (len <= idx)
+               return;
+
+       for (i = 0; i < len && i < USB_BUFLEN; i++)
+               snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
+
+       dev_info(dev, "%sx data: %s (length=%d)\n",
+                (out ? "t" : "r"), codes, len);
+
+       if (out)
+               strcpy(inout, "Request\0");
+       else
+               strcpy(inout, "Got\0");
+
+       cmd    = buf[idx] & 0xff;
+       subcmd = buf[idx + 1] & 0xff;
+       data1  = buf[idx + 2] & 0xff;
+       data2  = buf[idx + 3] & 0xff;
+
+       switch (cmd) {
+       case 0x00:
+               if (subcmd == 0xff && data1 == 0xaa)
+                       dev_info(dev, "Device reset requested\n");
+               else
+                       dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+                                cmd, subcmd);
+               break;
+       case 0xff:
+               switch (subcmd) {
+               case 0x0b:
+                       if (len == 2)
+                               dev_info(dev, "Get hw/sw rev?\n");
+                       else
+                               dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
+                                        "0x%02x 0x%02x\n", data1, data2,
+                                        buf[idx + 4], buf[idx + 5]);
+                       break;
+               case 0xaa:
+                       dev_info(dev, "Device reset requested\n");
+                       break;
+               case 0xfe:
+                       dev_info(dev, "Previous command not supported\n");
+                       break;
+               case 0x18:
+               case 0x1b:
+               default:
+                       dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+                                cmd, subcmd);
+                       break;
+               }
+               break;
+       case 0x9f:
+               switch (subcmd) {
+               case 0x03:
+                       dev_info(dev, "Ping\n");
+                       break;
+               case 0x04:
+                       dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
+                                data1, data2);
+                       break;
+               case 0x06:
+                       dev_info(dev, "%s carrier mode and freq of "
+                                "0x%02x 0x%02x\n", inout, data1, data2);
+                       break;
+               case 0x07:
+                       dev_info(dev, "Get carrier mode and freq\n");
+                       break;
+               case 0x08:
+                       dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
+                                inout, data1);
+                       break;
+               case 0x0c:
+                       /* value is in units of 50us, so x*50/100 or x/2 ms */
+                       dev_info(dev, "%s receive timeout of %d ms\n",
+                                inout, ((data1 << 8) | data2) / 2);
+                       break;
+               case 0x0d:
+                       dev_info(dev, "Get receive timeout\n");
+                       break;
+               case 0x13:
+                       dev_info(dev, "Get transmit blaster mask\n");
+                       break;
+               case 0x14:
+                       dev_info(dev, "%s %s-range receive sensor in use\n",
+                                inout, data1 == 0x02 ? "short" : "long");
+                       break;
+               case 0x15:
+                       if (len == 2)
+                               dev_info(dev, "Get receive sensor\n");
+                       else
+                               dev_info(dev, "Received pulse count is %d\n",
+                                        ((data1 << 8) | data2));
+                       break;
+               case 0xfe:
+                       dev_info(dev, "Error! Hardware is likely wedged...\n");
+                       break;
+               case 0x05:
+               case 0x09:
+               case 0x0f:
+               default:
+                       dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+                                cmd, subcmd);
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void usb_async_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct mceusb_dev *ir;
+       int len;
+
+       if (!urb)
+               return;
+
+       ir = urb->context;
+       if (ir) {
+               len = urb->actual_length;
+
+               dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
+                       urb->status, len);
+
+               if (debug)
+                       mceusb_dev_printdata(ir, urb->transfer_buffer,
+                                            len, true);
+       }
+
+}
+
+/* request incoming or send outgoing usb packet - used to initialize remote */
+static void mce_request_packet(struct mceusb_dev *ir,
+                              struct usb_endpoint_descriptor *ep,
+                              unsigned char *data, int size, int urb_type)
+{
+       int res;
+       struct urb *async_urb;
+       struct device *dev = ir->dev;
+       unsigned char *async_buf;
+
+       if (urb_type == MCEUSB_TX) {
+               async_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (unlikely(!async_urb)) {
+                       dev_err(dev, "Error, couldn't allocate urb!\n");
+                       return;
+               }
+
+               async_buf = kzalloc(size, GFP_KERNEL);
+               if (!async_buf) {
+                       dev_err(dev, "Error, couldn't allocate buf!\n");
+                       usb_free_urb(async_urb);
+                       return;
+               }
+
+               /* outbound data */
+               usb_fill_int_urb(async_urb, ir->usbdev,
+                       usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
+                       async_buf, size, (usb_complete_t) usb_async_callback,
+                       ir, ep->bInterval);
+               memcpy(async_buf, data, size);
+
+       } else if (urb_type == MCEUSB_RX) {
+               /* standard request */
+               async_urb = ir->urb_in;
+               ir->send_flags = RECV_FLAG_IN_PROGRESS;
+
+       } else {
+               dev_err(dev, "Error! Unknown urb type %d\n", urb_type);
+               return;
+       }
+
+       dev_dbg(dev, "receive request called (size=%#x)\n", size);
+
+       async_urb->transfer_buffer_length = size;
+       async_urb->dev = ir->usbdev;
+
+       res = usb_submit_urb(async_urb, GFP_ATOMIC);
+       if (res) {
+               dev_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+               return;
+       }
+       dev_dbg(dev, "receive request complete (res=%d)\n", res);
+}
+
+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+       mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX);
+}
+
+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+       mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
+}
+
+/* Send data out the IR blaster port(s) */
+static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
+{
+       struct mceusb_dev *ir = priv;
+       int i, ret = 0;
+       int count, cmdcount = 0;
+       unsigned char *cmdbuf; /* MCE command buffer */
+       long signal_duration = 0; /* Singnal length in us */
+       struct timeval start_time, end_time;
+
+       do_gettimeofday(&start_time);
+
+       count = n / sizeof(int);
+
+       cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
+       if (!cmdbuf)
+               return -ENOMEM;
+
+       /* MCE tx init header */
+       cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
+       cmdbuf[cmdcount++] = 0x08;
+       cmdbuf[cmdcount++] = ir->tx_mask;
+
+       /* Generate mce packet data */
+       for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
+               signal_duration += txbuf[i];
+               txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
+
+               do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
+
+                       /* Insert mce packet header every 4th entry */
+                       if ((cmdcount < MCE_CMDBUF_SIZE) &&
+                           (cmdcount - MCE_TX_HEADER_LENGTH) %
+                            MCE_CODE_LENGTH == 0)
+                               cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
+
+                       /* Insert mce packet data */
+                       if (cmdcount < MCE_CMDBUF_SIZE)
+                               cmdbuf[cmdcount++] =
+                                       (txbuf[i] < MCE_PULSE_BIT ?
+                                        txbuf[i] : MCE_MAX_PULSE_LENGTH) |
+                                        (i & 1 ? 0x00 : MCE_PULSE_BIT);
+                       else {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+               } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
+                        (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
+       }
+
+       /* Fix packet length in last header */
+       cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
+               0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
+
+       /* Check if we have room for the empty packet at the end */
+       if (cmdcount >= MCE_CMDBUF_SIZE) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* All mce commands end with an empty packet (0x80) */
+       cmdbuf[cmdcount++] = 0x80;
+
+       /* Transmit the command to the mce device */
+       mce_async_out(ir, cmdbuf, cmdcount);
+
+       /*
+        * The lircd gap calculation expects the write function to
+        * wait the time it takes for the ircommand to be sent before
+        * it returns.
+        */
+       do_gettimeofday(&end_time);
+       signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
+                          (end_time.tv_sec - start_time.tv_sec) * 1000000;
+
+       /* delay with the closest number of ticks */
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(usecs_to_jiffies(signal_duration));
+
+out:
+       kfree(cmdbuf);
+       return ret ? ret : n;
+}
+
+/* Sets active IR outputs -- mce devices typically (all?) have two */
+static int mceusb_set_tx_mask(void *priv, u32 mask)
+{
+       struct mceusb_dev *ir = priv;
+
+       if (ir->flags.tx_mask_inverted)
+               ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1;
+       else
+               ir->tx_mask = mask;
+
+       return 0;
+}
+
+/* Sets the send carrier frequency and mode */
+static int mceusb_set_tx_carrier(void *priv, u32 carrier)
+{
+       struct mceusb_dev *ir = priv;
+       int clk = 10000000;
+       int prescaler = 0, divisor = 0;
+       unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
+
+       /* Carrier has changed */
+       if (ir->carrier != carrier) {
+
+               if (carrier == 0) {
+                       ir->carrier = carrier;
+                       cmdbuf[2] = 0x01;
+                       cmdbuf[3] = 0x80;
+                       dev_dbg(ir->dev, "%s: disabling carrier "
+                               "modulation\n", __func__);
+                       mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+                       return carrier;
+               }
+
+               for (prescaler = 0; prescaler < 4; ++prescaler) {
+                       divisor = (clk >> (2 * prescaler)) / carrier;
+                       if (divisor <= 0xFF) {
+                               ir->carrier = carrier;
+                               cmdbuf[2] = prescaler;
+                               cmdbuf[3] = divisor;
+                               dev_dbg(ir->dev, "%s: requesting %u HZ "
+                                       "carrier\n", __func__, carrier);
+
+                               /* Transmit new carrier to mce device */
+                               mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+                               return carrier;
+                       }
+               }
+
+               return -EINVAL;
+
+       }
+
+       return carrier;
+}
+
+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
+{
+       struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
+       int i, start_index = 0;
+       u8 hdr = MCE_CONTROL_HEADER;
+
+       /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+       if (ir->flags.microsoft_gen1)
+               start_index = 2;
+
+       for (i = start_index; i < buf_len;) {
+               if (ir->rem == 0) {
+                       /* decode mce packets of the form (84),AA,BB,CC,DD */
+                       /* IR data packets can span USB messages - rem */
+                       hdr = ir->buf_in[i];
+                       ir->rem = (hdr & MCE_PACKET_LENGTH_MASK);
+                       ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK);
+                       dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n",
+                               ir->rem, ir->cmd);
+                       i++;
+               }
+
+               /* don't process MCE commands */
+               if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) {
+                       ir->rem = 0;
+                       return;
+               }
+
+               for (; (ir->rem > 0) && (i < buf_len); i++) {
+                       ir->rem--;
+
+                       rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
+                       rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
+                                        * MCE_TIME_UNIT * 1000;
+
+                       if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
+                               if (ir->rawir.pulse == rawir.pulse)
+                                       ir->rawir.duration += rawir.duration;
+                               else {
+                                       ir->rawir.duration = rawir.duration;
+                                       ir->rawir.pulse = rawir.pulse;
+                               }
+                               continue;
+                       }
+                       rawir.duration += ir->rawir.duration;
+                       ir->rawir.duration = 0;
+                       ir->rawir.pulse = rawir.pulse;
+
+                       dev_dbg(ir->dev, "Storing %s with duration %d\n",
+                               rawir.pulse ? "pulse" : "space",
+                               rawir.duration);
+
+                       ir_raw_event_store(ir->idev, &rawir);
+               }
+
+               if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f)
+                       ir->rem = 0;
+
+               dev_dbg(ir->dev, "calling ir_raw_event_handle\n");
+               ir_raw_event_handle(ir->idev);
+       }
+}
+
+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
+{
+       struct mceusb_dev *ir;
+       int buf_len;
+
+       if (!urb)
+               return;
+
+       ir = urb->context;
+       if (!ir) {
+               usb_unlink_urb(urb);
+               return;
+       }
+
+       buf_len = urb->actual_length;
+
+       if (debug)
+               mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false);
+
+       if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
+               ir->send_flags = SEND_FLAG_COMPLETE;
+               dev_dbg(&ir->irdev->dev, "setup answer received %d bytes\n",
+                       buf_len);
+       }
+
+       switch (urb->status) {
+       /* success */
+       case 0:
+               mceusb_process_ir_data(ir, buf_len);
+               break;
+
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               usb_unlink_urb(urb);
+               return;
+
+       case -EPIPE:
+       default:
+               break;
+       }
+
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void mceusb_gen1_init(struct mceusb_dev *ir)
+{
+       int ret;
+       int maxp = ir->len_in;
+       struct device *dev = ir->dev;
+       char *data;
+
+       data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "%s: memory allocation failed!\n", __func__);
+               return;
+       }
+
+       /*
+        * This is a strange one. Windows issues a set address to the device
+        * on the receive control pipe and expect a certain value pair back
+        */
+       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+                             USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
+                             data, USB_CTRL_MSG_SZ, HZ * 3);
+       dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+       dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
+               __func__, data[0], data[1]);
+
+       /* set feature: bit rate 38400 bps */
+       ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+                             USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
+                             0xc04e, 0x0000, NULL, 0, HZ * 3);
+
+       dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+
+       /* bRequest 4: set char length to 8 bits */
+       ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+                             4, USB_TYPE_VENDOR,
+                             0x0808, 0x0000, NULL, 0, HZ * 3);
+       dev_dbg(dev, "%s - retB = %d\n", __func__, ret);
+
+       /* bRequest 2: set handshaking to use DTR/DSR */
+       ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+                             2, USB_TYPE_VENDOR,
+                             0x0000, 0x0100, NULL, 0, HZ * 3);
+       dev_dbg(dev, "%s - retC = %d\n", __func__, ret);
+
+       /* device reset */
+       mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+       mce_sync_in(ir, NULL, maxp);
+
+       /* get hw/sw revision? */
+       mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+       mce_sync_in(ir, NULL, maxp);
+
+       kfree(data);
+};
+
+static void mceusb_gen2_init(struct mceusb_dev *ir)
+{
+       int maxp = ir->len_in;
+
+       /* device reset */
+       mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+       mce_sync_in(ir, NULL, maxp);
+
+       /* get hw/sw revision? */
+       mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+       mce_sync_in(ir, NULL, maxp);
+
+       /* unknown what the next two actually return... */
+       mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+       mce_sync_in(ir, NULL, maxp);
+       mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
+       mce_sync_in(ir, NULL, maxp);
+}
+
+static void mceusb_get_parameters(struct mceusb_dev *ir)
+{
+       int maxp = ir->len_in;
+
+       /* get the carrier and frequency */
+       mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
+       mce_sync_in(ir, NULL, maxp);
+
+       /* get the transmitter bitmask */
+       mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+       mce_sync_in(ir, NULL, maxp);
+
+       /* get receiver timeout value */
+       mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
+       mce_sync_in(ir, NULL, maxp);
+
+       /* get receiver sensor setting */
+       mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+       mce_sync_in(ir, NULL, maxp);
+}
+
+static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
+{
+       struct input_dev *idev;
+       struct ir_dev_props *props;
+       struct ir_input_dev *irdev;
+       struct device *dev = ir->dev;
+       int ret = -ENODEV;
+
+       idev = input_allocate_device();
+       if (!idev) {
+               dev_err(dev, "remote input dev allocation failed\n");
+               goto idev_alloc_failed;
+       }
+
+       ret = -ENOMEM;
+       props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
+       if (!props) {
+               dev_err(dev, "remote ir dev props allocation failed\n");
+               goto props_alloc_failed;
+       }
+
+       irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
+       if (!irdev) {
+               dev_err(dev, "remote ir input dev allocation failed\n");
+               goto ir_dev_alloc_failed;
+       }
+
+       snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
+                "Infrared Remote Transceiver (%04x:%04x)",
+                le16_to_cpu(ir->usbdev->descriptor.idVendor),
+                le16_to_cpu(ir->usbdev->descriptor.idProduct));
+
+       idev->name = ir->name;
+       usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
+       strlcat(ir->phys, "/input0", sizeof(ir->phys));
+       idev->phys = ir->phys;
+
+       props->priv = ir;
+       props->driver_type = RC_DRIVER_IR_RAW;
+       props->allowed_protos = IR_TYPE_ALL;
+       props->s_tx_mask = mceusb_set_tx_mask;
+       props->s_tx_carrier = mceusb_set_tx_carrier;
+       props->tx_ir = mceusb_tx_ir;
+
+       ir->props = props;
+       ir->irdev = irdev;
+
+       input_set_drvdata(idev, irdev);
+
+       ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
+       if (ret < 0) {
+               dev_err(dev, "remote input device register failed\n");
+               goto irdev_failed;
+       }
+
+       return idev;
+
+irdev_failed:
+       kfree(irdev);
+ir_dev_alloc_failed:
+       kfree(props);
+props_alloc_failed:
+       input_free_device(idev);
+idev_alloc_failed:
+       return NULL;
+}
+
+static int __devinit mceusb_dev_probe(struct usb_interface *intf,
+                                     const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *idesc;
+       struct usb_endpoint_descriptor *ep = NULL;
+       struct usb_endpoint_descriptor *ep_in = NULL;
+       struct usb_endpoint_descriptor *ep_out = NULL;
+       struct usb_host_config *config;
+       struct mceusb_dev *ir = NULL;
+       int pipe, maxp, i;
+       char buf[63], name[128] = "";
+       bool is_gen3;
+       bool is_microsoft_gen1;
+       bool tx_mask_inverted;
+
+       dev_dbg(&intf->dev, ": %s called\n", __func__);
+
+       config = dev->actconfig;
+       idesc  = intf->cur_altsetting;
+
+       is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0;
+       is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0;
+       tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1;
+
+       /* step through the endpoints to find first bulk in and out endpoint */
+       for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
+               ep = &idesc->endpoint[i].desc;
+
+               if ((ep_in == NULL)
+                       && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                           == USB_DIR_IN)
+                       && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                           == USB_ENDPOINT_XFER_BULK)
+                       || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                           == USB_ENDPOINT_XFER_INT))) {
+
+                       ep_in = ep;
+                       ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
+                       ep_in->bInterval = 1;
+                       dev_dbg(&intf->dev, ": acceptable inbound endpoint "
+                               "found\n");
+               }
+
+               if ((ep_out == NULL)
+                       && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                           == USB_DIR_OUT)
+                       && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                           == USB_ENDPOINT_XFER_BULK)
+                       || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                           == USB_ENDPOINT_XFER_INT))) {
+
+                       ep_out = ep;
+                       ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
+                       ep_out->bInterval = 1;
+                       dev_dbg(&intf->dev, ": acceptable outbound endpoint "
+                               "found\n");
+               }
+       }
+       if (ep_in == NULL) {
+               dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n");
+               return -ENODEV;
+       }
+
+       pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
+       if (!ir)
+               goto mem_alloc_fail;
+
+       ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
+       if (!ir->buf_in)
+               goto buf_in_alloc_fail;
+
+       ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ir->urb_in)
+               goto urb_in_alloc_fail;
+
+       ir->usbdev = dev;
+       ir->dev = &intf->dev;
+       ir->len_in = maxp;
+       ir->flags.microsoft_gen1 = is_microsoft_gen1;
+       ir->flags.tx_mask_inverted = tx_mask_inverted;
+
+       /* Saving usb interface data for use by the transmitter routine */
+       ir->usb_ep_in = ep_in;
+       ir->usb_ep_out = ep_out;
+
+       if (dev->descriptor.iManufacturer
+           && usb_string(dev, dev->descriptor.iManufacturer,
+                         buf, sizeof(buf)) > 0)
+               strlcpy(name, buf, sizeof(name));
+       if (dev->descriptor.iProduct
+           && usb_string(dev, dev->descriptor.iProduct,
+                         buf, sizeof(buf)) > 0)
+               snprintf(name + strlen(name), sizeof(name) - strlen(name),
+                        " %s", buf);
+
+       ir->idev = mceusb_init_input_dev(ir);
+       if (!ir->idev)
+               goto input_dev_fail;
+
+       /* flush buffers on the device */
+       mce_sync_in(ir, NULL, maxp);
+       mce_sync_in(ir, NULL, maxp);
+
+       /* wire up inbound data handler */
+       usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
+               maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
+       ir->urb_in->transfer_dma = ir->dma_in;
+       ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* initialize device */
+       if (ir->flags.microsoft_gen1)
+               mceusb_gen1_init(ir);
+       else if (!is_gen3)
+               mceusb_gen2_init(ir);
+
+       mceusb_get_parameters(ir);
+
+       mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
+
+       usb_set_intfdata(intf, ir);
+
+       dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
+                dev->bus->busnum, dev->devnum);
+
+       return 0;
+
+       /* Error-handling path */
+input_dev_fail:
+       usb_free_urb(ir->urb_in);
+urb_in_alloc_fail:
+       usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
+buf_in_alloc_fail:
+       kfree(ir);
+mem_alloc_fail:
+       dev_err(&intf->dev, "%s: device setup failed!\n", __func__);
+
+       return -ENOMEM;
+}
+
+
+static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct mceusb_dev *ir = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+
+       if (!ir)
+               return;
+
+       ir->usbdev = NULL;
+       ir_input_unregister(ir->idev);
+       usb_kill_urb(ir->urb_in);
+       usb_free_urb(ir->urb_in);
+       usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+       kfree(ir);
+}
+
+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct mceusb_dev *ir = usb_get_intfdata(intf);
+       dev_info(ir->dev, "suspend\n");
+       usb_kill_urb(ir->urb_in);
+       return 0;
+}
+
+static int mceusb_dev_resume(struct usb_interface *intf)
+{
+       struct mceusb_dev *ir = usb_get_intfdata(intf);
+       dev_info(ir->dev, "resume\n");
+       if (usb_submit_urb(ir->urb_in, GFP_ATOMIC))
+               return -EIO;
+       return 0;
+}
+
+static struct usb_driver mceusb_dev_driver = {
+       .name =         DRIVER_NAME,
+       .probe =        mceusb_dev_probe,
+       .disconnect =   mceusb_dev_disconnect,
+       .suspend =      mceusb_dev_suspend,
+       .resume =       mceusb_dev_resume,
+       .reset_resume = mceusb_dev_resume,
+       .id_table =     mceusb_dev_table
+};
+
+static int __init mceusb_dev_init(void)
+{
+       int ret;
+
+       ret = usb_register(&mceusb_dev_driver);
+       if (ret < 0)
+               printk(KERN_ERR DRIVER_NAME
+                      ": usb register failed, result = %d\n", ret);
+
+       return ret;
+}
+
+static void __exit mceusb_dev_exit(void)
+{
+       usb_deregister(&mceusb_dev_driver);
+}
+
+module_init(mceusb_dev_init);
+module_exit(mceusb_dev_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, mceusb_dev_table);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
index 7364b9642d005c0579838c4efdf7c61888767f98..4da2a54cb8bde6b1a9052df74300418432f9a7f3 100644 (file)
@@ -57,7 +57,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
        BUG_ON(in_interrupt());
 
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_unmap(q, dma);
+       videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
index 74e2b56ecb5bb09b13135640872efb32445165b3..8224c301d0508c2bea379dc953b96947a2838166 100644 (file)
@@ -375,7 +375,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
 
 static int vbi_open(struct saa7146_dev *dev, struct file *file)
 {
-       struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+       struct saa7146_fh *fh = file->private_data;
 
        u32 arbtr_ctrl  = saa7146_read(dev, PCI_BT_V1);
        int ret = 0;
@@ -437,7 +437,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
 
 static void vbi_close(struct saa7146_dev *dev, struct file *file)
 {
-       struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+       struct saa7146_fh *fh = file->private_data;
        struct saa7146_vv *vv = dev->vv_data;
        DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
 
index b8b2c551a1e2d07aae91c983103c29fb52820080..a212a91a30f081ed59f80c4c0dd68562e7bdef00 100644 (file)
@@ -1370,7 +1370,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
 
 static int video_open(struct saa7146_dev *dev, struct file *file)
 {
-       struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+       struct saa7146_fh *fh = file->private_data;
        struct saa7146_format *sfmt;
 
        fh->video_fmt.width = 384;
@@ -1394,7 +1394,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
 
 static void video_close(struct saa7146_dev *dev, struct file *file)
 {
-       struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+       struct saa7146_fh *fh = file->private_data;
        struct saa7146_vv *vv = dev->vv_data;
        struct videobuf_queue *q = &fh->video_q;
        int err;
index b2e15456d5f36600c32c78542c42d7188634071a..7955e49a34405f73b484ec742fec0dd913873a4b 100644 (file)
@@ -1249,7 +1249,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
                                     struct tda18271_config *cfg)
 {
        struct tda18271_priv *priv = NULL;
-       int instance;
+       int instance, ret;
 
        mutex_lock(&tda18271_list_mutex);
 
@@ -1268,10 +1268,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
                priv->cal_initialized = false;
                mutex_init(&priv->lock);
 
-               if (tda_fail(tda18271_get_id(fe)))
+               ret = tda18271_get_id(fe);
+               if (tda_fail(ret))
                        goto fail;
 
-               if (tda_fail(tda18271_assign_map_layout(fe)))
+               ret = tda18271_assign_map_layout(fe);
+               if (tda_fail(ret))
                        goto fail;
 
                mutex_lock(&priv->lock);
index 8cf2ab609d5ec2ec984b4095dda436f52a69a0fd..f8ee29e6059c982e8e8ddce5cd0cbe28d78b58ed 100644 (file)
@@ -546,14 +546,11 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
        struct tuner_simple_priv *priv = fe->tuner_priv;
        u8 config, cb;
        u16 div;
-       struct tunertype *tun;
        u8 buffer[4];
        int rc, IFPCoff, i;
        enum param_type desired_type;
        struct tuner_params *t_params;
 
-       tun = priv->tun;
-
        /* IFPCoff = Video Intermediate Frequency - Vif:
                940  =16*58.75  NTSC/J (Japan)
                732  =16*45.75  M/N STD
index 432003dded7cc65e9971eca7eaba02bb2594e81f..d2b2c12a55618083871f154cb0dda7fb6062b565 100644 (file)
@@ -217,6 +217,7 @@ static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
        return XC_RESULT_SUCCESS;
 }
 
+#if 0
 /* This routine is never used because the only time we read data from the
    i2c bus is when we read registers, and we want that to be an atomic i2c
    transaction in case we are on a multi-master bus */
@@ -231,6 +232,27 @@ static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
        }
        return 0;
 }
+#endif
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+       u8 buf[2] = { reg >> 8, reg & 0xff };
+       u8 bval[2] = { 0, 0 };
+       struct i2c_msg msg[2] = {
+               { .addr = priv->i2c_props.addr,
+                       .flags = 0, .buf = &buf[0], .len = 2 },
+               { .addr = priv->i2c_props.addr,
+                       .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+       };
+
+       if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+               printk(KERN_WARNING "xc5000: I2C read failed\n");
+               return -EREMOTEIO;
+       }
+
+       *val = (bval[0] << 8) | bval[1];
+       return XC_RESULT_SUCCESS;
+}
 
 static void xc_wait(int wait_ms)
 {
@@ -275,20 +297,14 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
        if (result == XC_RESULT_SUCCESS) {
                /* wait for busy flag to clear */
                while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
-                       buf[0] = 0;
-                       buf[1] = XREG_BUSY;
-
-                       result = xc_send_i2c_data(priv, buf, 2);
+                       result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
                        if (result == XC_RESULT_SUCCESS) {
-                               result = xc_read_i2c_data(priv, buf, 2);
-                               if (result == XC_RESULT_SUCCESS) {
-                                       if ((buf[0] == 0) && (buf[1] == 0)) {
-                                               /* busy flag cleared */
+                               if ((buf[0] == 0) && (buf[1] == 0)) {
+                                       /* busy flag cleared */
                                        break;
-                                       } else {
-                                               xc_wait(5); /* wait 5 ms */
-                                               WatchDogTimer--;
-                                       }
+                               } else {
+                                       xc_wait(5); /* wait 5 ms */
+                                       WatchDogTimer--;
                                }
                        }
                }
@@ -526,25 +542,6 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
        return found;
 }
 
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-{
-       u8 buf[2] = { reg >> 8, reg & 0xff };
-       u8 bval[2] = { 0, 0 };
-       struct i2c_msg msg[2] = {
-               { .addr = priv->i2c_props.addr,
-                       .flags = 0, .buf = &buf[0], .len = 2 },
-               { .addr = priv->i2c_props.addr,
-                       .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
-       };
-
-       if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
-               printk(KERN_WARNING "xc5000: I2C read failed\n");
-               return -EREMOTEIO;
-       }
-
-       *val = (bval[0] << 8) | bval[1];
-       return XC_RESULT_SUCCESS;
-}
 
 static int xc5000_fwupload(struct dvb_frontend *fe)
 {
index 770243c720d2e3d06a5fb733ff05ba505c0eb88b..cf87051628458efd1035b172d22c40f3b3e00c8a 100644 (file)
@@ -565,7 +565,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct
        int result = 0;
 
        lock_kernel();
-       dvbdev = (struct dvb_device *)file->private_data;
+       dvbdev = file->private_data;
        state = (struct dst_state *)dvbdev->priv;
        p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
        p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
index 425862ffb2856b1e3b9019816ef6b003e7053f3f..0042306ea11b8539eeba3a8f41f73fd970e6e5f7 100644 (file)
@@ -207,7 +207,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
        }
        /* TODO */
        dvbdev->users--;
-       if(dvbdev->users==-1 && dmxdev->exit==1) {
+       if (dvbdev->users == 1 && dmxdev->exit == 1) {
                fops_put(file->f_op);
                file->f_op = NULL;
                mutex_unlock(&dmxdev->mutex);
index ef259a0718ac3176befc7e283f67145f5d0d4d0c..cb97e6b8543295971d30f8b21c233791a725f26e 100644 (file)
@@ -1318,8 +1318,11 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
 
                fragbuf[0] = connection_id;
                fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
-               if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)
+               status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+               if (status) {
+                       status = -EFAULT;
                        goto exit;
+               }
 
                timeout = jiffies + HZ / 2;
                written = 0;
@@ -1494,8 +1497,11 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
 
        hdr[0] = slot;
        hdr[1] = connection_id;
-       if ((status = copy_to_user(buf, hdr, 2)) != 0)
+       status = copy_to_user(buf, hdr, 2);
+       if (status) {
+               status = -EFAULT;
                goto exit;
+       }
        status = pktlen;
 
 exit:
index 977ddba3e235cc7994d428f1c80886ade064abf6..4a88a3e4db2b5d4a7e510523a375abf90a95d647 100644 (file)
@@ -1130,13 +1130,9 @@ static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t
        if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
                return -EINVAL;
 
-       p = kmalloc(count, GFP_USER);
-       if (!p)
-               return -ENOMEM;
-       if (copy_from_user(p, buf, count)) {
-               kfree(p);
-               return -EFAULT;
-       }
+       p = memdup_user(buf, count);
+       if (IS_ERR(p))
+               return PTR_ERR(p);
        if (mutex_lock_interruptible(&dvbdemux->mutex)) {
                kfree(p);
                return -ERESTARTSYS;
index 44ae89ecef94ba4701ad2cb600e42c3d7e5e7692..4d45b7d6b3fb248f267f4754601120c591e8bcb3 100644 (file)
@@ -465,7 +465,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
                fepriv->delay = fepriv->min_delay;
 
-               /* peform a tune */
+               /* perform a tune */
                retval = dvb_frontend_swzigzag_autotune(fe,
                                                        fepriv->check_wrapped);
                if (retval < 0) {
@@ -791,7 +791,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
        return 0;
 }
 
-static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
                                        u32 *freq_min, u32 *freq_max)
 {
        *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
@@ -815,7 +815,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
        u32 freq_max;
 
        /* range check: frequency */
-       dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+       dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
        if ((freq_min && parms->frequency < freq_min) ||
            (freq_max && parms->frequency > freq_max)) {
                printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
@@ -1627,7 +1627,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
        case FE_GET_INFO: {
                struct dvb_frontend_info* info = parg;
                memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
-               dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
+               dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
 
                /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
                 * do it, it is done for it. */
@@ -1726,7 +1726,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                         * (stv0299 for instance) take longer than 8msec to
                         * respond to a set_voltage command.  Those switches
                         * need custom routines to switch properly.  For all
-                        * other frontends, the following shoule work ok.
+                        * other frontends, the following should work ok.
                         * Dish network legacy switches (as used by Dish500)
                         * are controlled by sending 9-bit command words
                         * spaced 8msec apart.
index b6cbb1dfc5f14d272731153dde3cff6d4567ff7c..a5c36372713318bf386e3e66802496e6b424a3da 100644 (file)
@@ -37,7 +37,7 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_a800_table[] = {
+static struct ir_scancode ir_codes_a800_table[] = {
        { 0x0201, KEY_PROG1 },       /* SOURCE */
        { 0x0200, KEY_POWER },       /* POWER */
        { 0x0205, KEY_1 },           /* 1 */
@@ -146,10 +146,12 @@ static struct dvb_usb_device_properties a800_properties = {
        .power_ctrl       = a800_power_ctrl,
        .identify_state   = a800_identify_state,
 
-       .rc_interval      = DEFAULT_RC_INTERVAL,
-       .rc_key_map       = ir_codes_a800_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_a800_table),
-       .rc_query         = a800_rc_query,
+       .rc.legacy = {
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = ir_codes_a800_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_a800_table),
+               .rc_query         = a800_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
index b41fa873b04dd1e883e5ce96e57d65ce00fabd27..696207fe37ec41e69943f28cc6b68021c21ff60b 100644 (file)
@@ -33,7 +33,7 @@ MODULE_PARM_DESC(debug,
 
 #define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
 
-struct dvb_usb_rc_key ir_codes_af9005_table[] = {
+struct ir_scancode ir_codes_af9005_table[] = {
 
        {0x01b7, KEY_POWER},
        {0x01a7, KEY_VOLUMEUP},
@@ -133,7 +133,7 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
                        for (i = 0; i < ir_codes_af9005_table_size; i++) {
                                if (rc5_custom(&ir_codes_af9005_table[i]) == cust
                                    && rc5_data(&ir_codes_af9005_table[i]) == dat) {
-                                       *event = ir_codes_af9005_table[i].event;
+                                       *event = ir_codes_af9005_table[i].keycode;
                                        *state = REMOTE_KEY_PRESSED;
                                        deb_decode
                                            ("key pressed, event %x\n", *event);
index cfd6107d5349c42835af05b33724f3355b2fc103..8ecba8848bcfb002f6bece7dbd32c8851e4dc68b 100644 (file)
@@ -54,50 +54,6 @@ struct af9005_device_state {
        int led_state;
 };
 
-static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
-                         u8 *rbuf, u16 rlen, int delay_ms)
-{
-       int actlen, ret = -ENOMEM;
-
-       if (wbuf == NULL || wlen == 0)
-               return -EINVAL;
-
-       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-               return ret;
-
-       deb_xfer(">>> ");
-       debug_dump(wbuf, wlen, deb_xfer);
-
-       ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
-                                                   2), wbuf, wlen,
-                          &actlen, 2000);
-
-       if (ret)
-               err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
-       else
-               ret = actlen != wlen ? -1 : 0;
-
-       /* an answer is expected, and no error before */
-       if (!ret && rbuf && rlen) {
-               if (delay_ms)
-                       msleep(delay_ms);
-
-               ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
-                                                           0x01), rbuf,
-                                  rlen, &actlen, 2000);
-
-               if (ret)
-                       err("recv bulk message failed: %d", ret);
-               else {
-                       deb_xfer("<<< ");
-                       debug_dump(rbuf, actlen, deb_xfer);
-               }
-       }
-
-       mutex_unlock(&d->usb_mutex);
-       return ret;
-}
-
 static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
                              int readwrite, int type, u8 * values, int len)
 {
@@ -146,7 +102,7 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
                obuf[8] = values[0];
        obuf[7] = command;
 
-       ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+       ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
        if (ret)
                return ret;
 
@@ -534,7 +490,7 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
        buf[6] = wlen;
        for (i = 0; i < wlen; i++)
                buf[7 + i] = wbuf[i];
-       ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+       ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
        if (ret)
                return ret;
        if (ibuf[2] != 0x27) {
@@ -581,7 +537,7 @@ int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
 
        obuf[6] = len;
        obuf[7] = address;
-       ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+       ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
        if (ret)
                return ret;
        if (ibuf[2] != 0x2b) {
@@ -882,7 +838,7 @@ static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
        obuf[2] = 0x40;         /* read remote */
        obuf[3] = 1;            /* rest of packet length */
        obuf[4] = st->sequence++;       /* sequence number */
-       ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+       ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
        if (ret) {
                err("rc query failed");
                return ret;
@@ -1069,10 +1025,15 @@ static struct dvb_usb_device_properties af9005_properties = {
 
        .i2c_algo = &af9005_i2c_algo,
 
-       .rc_interval = 200,
-       .rc_key_map = NULL,
-       .rc_key_map_size = 0,
-       .rc_query = af9005_rc_query,
+       .rc.legacy = {
+               .rc_interval = 200,
+               .rc_key_map = NULL,
+               .rc_key_map_size = 0,
+               .rc_query = af9005_rc_query,
+       },
+
+       .generic_bulk_ctrl_endpoint          = 2,
+       .generic_bulk_ctrl_endpoint_response = 1,
 
        .num_device_descs = 3,
        .devices = {
@@ -1113,10 +1074,10 @@ static int __init af9005_usb_module_init(void)
        rc_keys_size = symbol_request(ir_codes_af9005_table_size);
        if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
                err("af9005_rc_decode function not found, disabling remote");
-               af9005_properties.rc_query = NULL;
+               af9005_properties.rc.legacy.rc_query = NULL;
        } else {
-               af9005_properties.rc_key_map = rc_keys;
-               af9005_properties.rc_key_map_size = *rc_keys_size;
+               af9005_properties.rc.legacy.rc_key_map = rc_keys;
+               af9005_properties.rc.legacy.rc_key_map_size = *rc_keys_size;
        }
 
        return 0;
index 088e7083a39b15c32273a046ce1552626968beb4..3c1fbd1c5d60400eed87d0d0ab315a87cb317311 100644 (file)
@@ -3490,7 +3490,7 @@ extern u8 regmask[8];
 /* remote control decoder */
 extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
                            u32 * event, int *state);
-extern struct dvb_usb_rc_key ir_codes_af9005_table[];
+extern struct ir_scancode ir_codes_af9005_table[];
 extern int ir_codes_af9005_table_size;
 
 #endif
index 66c7c3ea7990e35a8cdac42f32e997142ea591a6..ea1ed3b4592a1d0bcb4c81df90fdb0bdbe468823 100644 (file)
@@ -735,7 +735,7 @@ error:
 
 struct af9015_setup {
        unsigned int id;
-       struct dvb_usb_rc_key *rc_key_map;
+       struct ir_scancode *rc_key_map;
        unsigned int rc_key_map_size;
        u8 *ir_table;
        unsigned int ir_table_size;
@@ -847,8 +847,8 @@ static void af9015_set_remote_config(struct usb_device *udev,
        }
 
        if (table) {
-               props->rc_key_map = table->rc_key_map;
-               props->rc_key_map_size = table->rc_key_map_size;
+               props->rc.legacy.rc_key_map = table->rc_key_map;
+               props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
                af9015_config.ir_table = table->ir_table;
                af9015_config.ir_table_size = table->ir_table_size;
        }
@@ -878,8 +878,8 @@ static int af9015_read_config(struct usb_device *udev)
        deb_info("%s: IR mode:%d\n", __func__, val);
        for (i = 0; i < af9015_properties_count; i++) {
                if (val == AF9015_IR_MODE_DISABLED) {
-                       af9015_properties[i].rc_key_map = NULL;
-                       af9015_properties[i].rc_key_map_size  = 0;
+                       af9015_properties[i].rc.legacy.rc_key_map = NULL;
+                       af9015_properties[i].rc.legacy.rc_key_map_size  = 0;
                } else
                        af9015_set_remote_config(udev, &af9015_properties[i]);
        }
@@ -1063,7 +1063,7 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        u8 buf[8];
        struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        int i, ret;
 
        memset(buf, 0, sizeof(buf));
@@ -1075,10 +1075,10 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        *event = 0;
        *state = REMOTE_NO_KEY_PRESSED;
 
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
                if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
                    rc5_data(&keymap[i]) == buf[2]) {
-                       *event = keymap[i].event;
+                       *event = keymap[i].keycode;
                        *state = REMOTE_KEY_PRESSED;
                        break;
                }
@@ -1299,6 +1299,7 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV2000DS)},
 /* 30 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_UB383_T)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_4)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1353,8 +1354,10 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .identify_state = af9015_identify_state,
 
-               .rc_query         = af9015_rc_query,
-               .rc_interval      = 150,
+               .rc.legacy = {
+                       .rc_query         = af9015_rc_query,
+                       .rc_interval      = 150,
+               },
 
                .i2c_algo = &af9015_i2c_algo,
 
@@ -1460,8 +1463,10 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .identify_state = af9015_identify_state,
 
-               .rc_query         = af9015_rc_query,
-               .rc_interval      = 150,
+               .rc.legacy = {
+                       .rc_query         = af9015_rc_query,
+                       .rc_interval      = 150,
+               },
 
                .i2c_algo = &af9015_i2c_algo,
 
@@ -1567,12 +1572,14 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .identify_state = af9015_identify_state,
 
-               .rc_query         = af9015_rc_query,
-               .rc_interval      = 150,
+               .rc.legacy = {
+                       .rc_query         = af9015_rc_query,
+                       .rc_interval      = 150,
+               },
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 8, /* max 9 */
+               .num_device_descs = 9, /* max 9 */
                .devices = {
                        {
                                .name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1617,6 +1624,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .cold_ids = {&af9015_usb_table[30], NULL},
                                .warm_ids = {NULL},
                        },
+                       {
+                               .name = "AverMedia AVerTV Volar M (A815Mac)",
+                               .cold_ids = {&af9015_usb_table[32], NULL},
+                               .warm_ids = {NULL},
+                       },
                }
        },
 };
index 63b2a4907b7ec1ec481bb17f9e01b50a5f38e458..c8e9349742eefdeb9ef96592555d03c6ddd3bd5a 100644 (file)
@@ -123,7 +123,7 @@ enum af9015_remote {
 
 /* LeadTek - Y04G0051 */
 /* Leadtek WinFast DTV Dongle Gold */
-static struct dvb_usb_rc_key ir_codes_af9015_table_leadtek[] = {
+static struct ir_scancode ir_codes_af9015_table_leadtek[] = {
        { 0x001e, KEY_1 },
        { 0x001f, KEY_2 },
        { 0x0020, KEY_3 },
@@ -227,7 +227,7 @@ static u8 af9015_ir_table_leadtek[] = {
 };
 
 /* TwinHan AzureWave AD-TU700(704J) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_twinhan[] = {
+static struct ir_scancode ir_codes_af9015_table_twinhan[] = {
        { 0x053f, KEY_POWER },
        { 0x0019, KEY_FAVORITES },    /* Favorite List */
        { 0x0004, KEY_TEXT },         /* Teletext */
@@ -338,7 +338,7 @@ static u8 af9015_ir_table_twinhan[] = {
 };
 
 /* A-Link DTU(m) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_a_link[] = {
+static struct ir_scancode ir_codes_af9015_table_a_link[] = {
        { 0x001e, KEY_1 },
        { 0x001f, KEY_2 },
        { 0x0020, KEY_3 },
@@ -381,7 +381,7 @@ static u8 af9015_ir_table_a_link[] = {
 };
 
 /* MSI DIGIVOX mini II V3.0 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi[] = {
+static struct ir_scancode ir_codes_af9015_table_msi[] = {
        { 0x001e, KEY_1 },
        { 0x001f, KEY_2 },
        { 0x0020, KEY_3 },
@@ -424,7 +424,7 @@ static u8 af9015_ir_table_msi[] = {
 };
 
 /* MYGICTV U718 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_mygictv[] = {
+static struct ir_scancode ir_codes_af9015_table_mygictv[] = {
        { 0x003d, KEY_SWITCHVIDEOMODE },
                                          /* TV / AV */
        { 0x0545, KEY_POWER },
@@ -550,7 +550,7 @@ static u8 af9015_ir_table_kworld[] = {
 };
 
 /* AverMedia Volar X */
-static struct dvb_usb_rc_key ir_codes_af9015_table_avermedia[] = {
+static struct ir_scancode ir_codes_af9015_table_avermedia[] = {
        { 0x053d, KEY_PROG1 },       /* SOURCE */
        { 0x0512, KEY_POWER },       /* POWER */
        { 0x051e, KEY_1 },           /* 1 */
@@ -656,7 +656,7 @@ static u8 af9015_ir_table_avermedia_ks[] = {
 };
 
 /* Digittrade DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_digittrade[] = {
+static struct ir_scancode ir_codes_af9015_table_digittrade[] = {
        { 0x010f, KEY_LAST },   /* RETURN */
        { 0x0517, KEY_TEXT },   /* TELETEXT */
        { 0x0108, KEY_EPG },    /* EPG */
@@ -719,7 +719,7 @@ static u8 af9015_ir_table_digittrade[] = {
 };
 
 /* TREKSTOR DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_trekstor[] = {
+static struct ir_scancode ir_codes_af9015_table_trekstor[] = {
        { 0x0704, KEY_AGAIN },          /* Home */
        { 0x0705, KEY_MUTE },           /* Mute */
        { 0x0706, KEY_UP },                     /* Up */
@@ -782,7 +782,7 @@ static u8 af9015_ir_table_trekstor[] = {
 };
 
 /* MSI DIGIVOX mini III */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi_digivox_iii[] = {
+static struct ir_scancode ir_codes_af9015_table_msi_digivox_iii[] = {
        { 0x0713, KEY_POWER },       /* [red power button] */
        { 0x073b, KEY_VIDEO },       /* Source */
        { 0x073e, KEY_ZOOM },        /* Zoom */
index faca1ad88a67d382be3c7d10301c57d5a5a20735..4685259e16141d52b35127e4c14df642daf9b99d 100644 (file)
@@ -377,7 +377,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        u8 buf[] = {CMD_GET_IR_CODE};
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        u8 ircode[2];
        int i, ret;
 
@@ -388,10 +388,10 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        *event = 0;
        *state = REMOTE_NO_KEY_PRESSED;
 
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
                if (rc5_custom(&keymap[i]) == ircode[0] &&
                    rc5_data(&keymap[i]) == ircode[1]) {
-                       *event = keymap[i].event;
+                       *event = keymap[i].keycode;
                        *state = REMOTE_KEY_PRESSED;
                        return 0;
                }
@@ -399,7 +399,7 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_anysee_table[] = {
+static struct ir_scancode ir_codes_anysee_table[] = {
        { 0x0100, KEY_0 },
        { 0x0101, KEY_1 },
        { 0x0102, KEY_2 },
@@ -463,6 +463,11 @@ static int anysee_probe(struct usb_interface *intf,
        if (intf->num_altsetting < 1)
                return -ENODEV;
 
+       /*
+        * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
+        * firmware from eeprom).  If dvb_usb_device_init() succeeds that
+        * means d is a valid pointer.
+        */
        ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
                adapter_nr);
        if (ret)
@@ -479,10 +484,7 @@ static int anysee_probe(struct usb_interface *intf,
        if (ret)
                return ret;
 
-       if (d)
-               ret = anysee_init(d);
-
-       return ret;
+       return anysee_init(d);
 }
 
 static struct usb_device_id anysee_table[] = {
@@ -518,10 +520,12 @@ static struct dvb_usb_device_properties anysee_properties = {
                }
        },
 
-       .rc_key_map       = ir_codes_anysee_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_anysee_table),
-       .rc_query         = anysee_rc_query,
-       .rc_interval      = 200,  /* windows driver uses 500ms */
+       .rc.legacy = {
+               .rc_key_map       = ir_codes_anysee_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_anysee_table),
+               .rc_query         = anysee_rc_query,
+               .rc_interval      = 200,  /* windows driver uses 500ms */
+       },
 
        .i2c_algo         = &anysee_i2c_algo,
 
index 6681ac1c56e35763983167409490b315e8da9ad0..62c58288469f5936af6937067f2994e54dd0d793 100644 (file)
@@ -386,7 +386,7 @@ static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_az6027_table[] = {
+static struct ir_scancode ir_codes_az6027_table[] = {
        { 0x01, KEY_1 },
        { 0x02, KEY_2 },
 };
@@ -1125,10 +1125,13 @@ static struct dvb_usb_device_properties az6027_properties = {
        .power_ctrl       = az6027_power_ctrl,
        .read_mac_address = az6027_read_mac_addr,
  */
-       .rc_key_map       = ir_codes_az6027_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_az6027_table),
-       .rc_interval      = 400,
-       .rc_query         = az6027_rc_query,
+       .rc.legacy = {
+               .rc_key_map       = ir_codes_az6027_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_az6027_table),
+               .rc_interval      = 400,
+               .rc_query         = az6027_rc_query,
+       },
+
        .i2c_algo         = &az6027_i2c_algo,
 
        .num_device_descs = 5,
index 5a9c14bdc980c5fe3e180d6aeada044a88d543b4..4f5aa83fc1fcb5c88ce6e185b19a01da993846ce 100644 (file)
@@ -84,7 +84,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_cinergyt2_table[] = {
+static struct ir_scancode ir_codes_cinergyt2_table[] = {
        { 0x0401, KEY_POWER },
        { 0x0402, KEY_1 },
        { 0x0403, KEY_2 },
@@ -217,10 +217,12 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
 
        .power_ctrl       = cinergyt2_power_ctrl,
 
-       .rc_interval      = 50,
-       .rc_key_map       = ir_codes_cinergyt2_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_cinergyt2_table),
-       .rc_query         = cinergyt2_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 50,
+               .rc_key_map       = ir_codes_cinergyt2_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_cinergyt2_table),
+               .rc_query         = cinergyt2_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 1,
 
index 11e9e85dac86b1f527ef43995e226ff1d14854fb..cd9f362c37b22c00507be6e6f705f942a9bc0482 100644 (file)
@@ -385,7 +385,7 @@ static int cxusb_d680_dmb_streaming_ctrl(
 
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        u8 ircode[4];
        int i;
 
@@ -394,10 +394,10 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        *event = 0;
        *state = REMOTE_NO_KEY_PRESSED;
 
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
                if (rc5_custom(&keymap[i]) == ircode[2] &&
                    rc5_data(&keymap[i]) == ircode[3]) {
-                       *event = keymap[i].event;
+                       *event = keymap[i].keycode;
                        *state = REMOTE_KEY_PRESSED;
 
                        return 0;
@@ -410,7 +410,7 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
                                    int *state)
 {
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        u8 ircode[4];
        int i;
        struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
@@ -422,10 +422,10 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
        if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
                return 0;
 
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
                if (rc5_custom(&keymap[i]) == ircode[1] &&
                    rc5_data(&keymap[i]) == ircode[2]) {
-                       *event = keymap[i].event;
+                       *event = keymap[i].keycode;
                        *state = REMOTE_KEY_PRESSED;
 
                        return 0;
@@ -438,7 +438,7 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
 static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
                int *state)
 {
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        u8 ircode[2];
        int i;
 
@@ -448,10 +448,10 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
        if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
                return 0;
 
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
                if (rc5_custom(&keymap[i]) == ircode[0] &&
                    rc5_data(&keymap[i]) == ircode[1]) {
-                       *event = keymap[i].event;
+                       *event = keymap[i].keycode;
                        *state = REMOTE_KEY_PRESSED;
 
                        return 0;
@@ -461,7 +461,7 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
+static struct ir_scancode ir_codes_dvico_mce_table[] = {
        { 0xfe02, KEY_TV },
        { 0xfe0e, KEY_MP3 },
        { 0xfe1a, KEY_DVD },
@@ -509,7 +509,7 @@ static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
        { 0xfe4e, KEY_POWER },
 };
 
-static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
+static struct ir_scancode ir_codes_dvico_portable_table[] = {
        { 0xfc02, KEY_SETUP },       /* Profile */
        { 0xfc43, KEY_POWER2 },
        { 0xfc06, KEY_EPG },
@@ -548,7 +548,7 @@ static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
        { 0xfc00, KEY_UNKNOWN },    /* HD */
 };
 
-static struct dvb_usb_rc_key ir_codes_d680_dmb_table[] = {
+static struct ir_scancode ir_codes_d680_dmb_table[] = {
        { 0x0038, KEY_UNKNOWN },        /* TV/AV */
        { 0x080c, KEY_ZOOM },
        { 0x0800, KEY_0 },
@@ -923,7 +923,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
                return -EIO;
 
        /* try to determine if there is no IR decoder on the I2C bus */
-       for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+       for (i = 0; adap->dev->props.rc.legacy.rc_key_map != NULL && i < 5; i++) {
                msleep(20);
                if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
                        goto no_IR;
@@ -931,7 +931,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
                        continue;
                if (ircode[2] + ircode[3] != 0xff) {
 no_IR:
-                       adap->dev->props.rc_key_map = NULL;
+                       adap->dev->props.rc.legacy.rc_key_map = NULL;
                        info("No IR receiver detected on this device.");
                        break;
                }
@@ -1451,10 +1451,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_portable_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-       .rc_query         = cxusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_portable_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+               .rc_query         = cxusb_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
@@ -1502,10 +1504,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc_interval      = 150,
-       .rc_key_map       = ir_codes_dvico_mce_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
-       .rc_query         = cxusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 150,
+               .rc_key_map       = ir_codes_dvico_mce_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
+               .rc_query         = cxusb_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
@@ -1561,10 +1565,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_portable_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-       .rc_query         = cxusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_portable_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+               .rc_query         = cxusb_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
        .num_device_descs = 1,
@@ -1611,10 +1617,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_portable_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-       .rc_query         = cxusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_portable_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+               .rc_query         = cxusb_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
@@ -1660,10 +1668,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_mce_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
-       .rc_query         = cxusb_bluebird2_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_mce_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
+               .rc_query         = cxusb_bluebird2_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
@@ -1708,10 +1718,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_portable_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-       .rc_query         = cxusb_bluebird2_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_portable_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+               .rc_query         = cxusb_bluebird2_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
@@ -1758,10 +1770,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_portable_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-       .rc_query         = cxusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_portable_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+               .rc_query         = cxusb_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
@@ -1849,10 +1863,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_dvico_mce_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
-       .rc_query         = cxusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_dvico_mce_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
+               .rc_query         = cxusb_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
@@ -1897,10 +1913,12 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_d680_dmb_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
-       .rc_query         = cxusb_d680_dmb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_d680_dmb_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
+               .rc_query         = cxusb_d680_dmb_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
@@ -1946,10 +1964,12 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_d680_dmb_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
-       .rc_query         = cxusb_d680_dmb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_d680_dmb_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
+               .rc_query         = cxusb_d680_dmb_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
index 83fc24a6c31a6b6b4b7836a028ea0d6a23f1d60b..c2c9d236ec7ea1d9bd6fc1a8baf192f1fde5e444 100644 (file)
@@ -60,6 +60,7 @@ extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 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(void *priv, u64 ir_type);
 
 extern int dib0700_device_count;
 extern int dvb_usb_dib0700_ir_proto;
index 4f961d2d1817e776699cebd54554f833ae14a66e..fe818348b8a36450357f2b19571b000afdcd873f 100644 (file)
@@ -13,10 +13,6 @@ int dvb_usb_dib0700_debug;
 module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
 
-int dvb_usb_dib0700_ir_proto = 1;
-module_param(dvb_usb_dib0700_ir_proto, int, 0644);
-MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
-
 static int nb_packet_buffer_size = 21;
 module_param(nb_packet_buffer_size, int, 0644);
 MODULE_PARM_DESC(nb_packet_buffer_size,
@@ -53,7 +49,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
        int status;
 
        deb_data(">>> ");
-       debug_dump(tx,txlen,deb_data);
+       debug_dump(tx, txlen, deb_data);
 
        status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
                tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
@@ -98,7 +94,7 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
                deb_info("ep 0 read error (status = %d)\n",status);
 
        deb_data("<<< ");
-       debug_dump(rx,rxlen,deb_data);
+       debug_dump(rx, rxlen, deb_data);
 
        return status; /* length in case of success */
 }
@@ -106,28 +102,29 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
 int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
 {
        u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
-       return dib0700_ctrl_wr(d,buf,3);
+       return dib0700_ctrl_wr(d, buf, sizeof(buf));
 }
 
 static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
 {
-    struct dib0700_state *st = d->priv;
-    u8 b[3];
-    int ret;
-
-    if (st->fw_version >= 0x10201) {
-       b[0] = REQUEST_SET_USB_XFER_LEN;
-       b[1] = (nb_ts_packets >> 8)&0xff;
-       b[2] = nb_ts_packets & 0xff;
-
-       deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
-
-       ret = dib0700_ctrl_wr(d, b, 3);
-    } else {
-       deb_info("this firmware does not allow to change the USB xfer len\n");
-       ret = -EIO;
-    }
-    return ret;
+       struct dib0700_state *st = d->priv;
+       u8 b[3];
+       int ret;
+
+       if (st->fw_version >= 0x10201) {
+               b[0] = REQUEST_SET_USB_XFER_LEN;
+               b[1] = (nb_ts_packets >> 8) & 0xff;
+               b[2] = nb_ts_packets & 0xff;
+
+               deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+               ret = dib0700_ctrl_wr(d, b, sizeof(b));
+       } else {
+               deb_info("this firmware does not allow to change the USB xfer len\n");
+               ret = -EIO;
+       }
+
+       return ret;
 }
 
 /*
@@ -178,7 +175,8 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                        value = ((en_start << 7) | (en_stop << 6) |
                                 (msg[i].len & 0x3F)) << 8 | i2c_dest;
                        /* I2C ctrl + FE bus; */
-                       index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+                       index = ((gen_mode << 6) & 0xC0) |
+                               ((bus_mode << 4) & 0x30);
 
                        result = usb_control_msg(d->udev,
                                                 usb_rcvctrlpipe(d->udev, 0),
@@ -198,11 +196,12 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                } else {
                        /* Write request */
                        buf[0] = REQUEST_NEW_I2C_WRITE;
-                       buf[1] = (msg[i].addr << 1);
+                       buf[1] = msg[i].addr << 1;
                        buf[2] = (en_start << 7) | (en_stop << 6) |
                                (msg[i].len & 0x3F);
                        /* I2C ctrl + FE bus; */
-                       buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+                       buf[3] = ((gen_mode << 6) & 0xC0) |
+                                ((bus_mode << 4) & 0x30);
                        /* The Actual i2c payload */
                        memcpy(&buf[4], msg[i].buf, msg[i].len);
 
@@ -240,7 +239,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
 
        for (i = 0; i < num; i++) {
                /* fill in the address */
-               buf[1] = (msg[i].addr << 1);
+               buf[1] = msg[i].addr << 1;
                /* fill the buffer */
                memcpy(&buf[2], msg[i].buf, msg[i].len);
 
@@ -368,7 +367,8 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
        u8 buf[260];
 
        while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
-               deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
+               deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
+                               hx.addr, hx.len, hx.chk);
 
                buf[0] = hx.len;
                buf[1] = (hx.addr >> 8) & 0xff;
@@ -408,16 +408,16 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
                                  REQUEST_GET_VERSION,
                                  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
                                  b, sizeof(b), USB_CTRL_GET_TIMEOUT);
-       fw_version = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+       fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
 
        /* set the buffer size - DVB-USB is allocating URB buffers
         * only after the firwmare download was successful */
        for (i = 0; i < dib0700_device_count; i++) {
                for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
                                adap_num++) {
-                       if (fw_version >= 0x10201)
+                       if (fw_version >= 0x10201) {
                                dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
-                       else {
+                       else {
                                /* for fw version older than 1.20.1,
                                 * the buffersize has to be n times 512 */
                                dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
@@ -453,7 +453,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        if (st->disable_streaming_master_mode == 1)
                b[2] = 0x00;
        else
-               b[2] = (0x01 << 4); /* Master mode */
+               b[2] = 0x01 << 4; /* Master mode */
 
        b[3] = 0x00;
 
@@ -466,11 +466,44 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
        b[2] |= st->channel_state;
 
-       deb_info("data for streaming: %x %x\n",b[1],b[2]);
+       deb_info("data for streaming: %x %x\n", b[1], b[2]);
 
        return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
+int dib0700_change_protocol(void *priv, u64 ir_type)
+{
+       struct dvb_usb_device *d = priv;
+       struct dib0700_state *st = d->priv;
+       u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
+       int new_proto, ret;
+
+       /* Set the IR mode */
+       if (ir_type == IR_TYPE_RC5)
+               new_proto = 1;
+       else if (ir_type == IR_TYPE_NEC)
+               new_proto = 0;
+       else if (ir_type == IR_TYPE_RC6) {
+               if (st->fw_version < 0x10200)
+                       return -EINVAL;
+
+               new_proto = 2;
+       } else
+               return -EINVAL;
+
+       rc_setup[1] = new_proto;
+
+       ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
+       if (ret < 0) {
+               err("ir protocol setup failed");
+               return ret;
+       }
+
+       d->props.rc.core.protocol = ir_type;
+
+       return ret;
+}
+
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY_V1_20 10
 
@@ -478,7 +511,13 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 struct dib0700_rc_response {
        u8 report_id;
        u8 data_state;
-       u16 system;
+       union {
+               u16 system16;
+               struct {
+                       u8 system;
+                       u8 not_system;
+               };
+       };
        u8 data;
        u8 not_data;
 };
@@ -487,14 +526,10 @@ struct dib0700_rc_response {
 static void dib0700_rc_urb_completion(struct urb *purb)
 {
        struct dvb_usb_device *d = purb->context;
-       struct dvb_usb_rc_key *keymap;
        struct dib0700_state *st;
-       struct dib0700_rc_response poll_reply;
-       u8 *buf;
-       int found = 0;
-       u32 event;
-       int state;
-       int i;
+       struct dib0700_rc_response *poll_reply;
+       u32 uninitialized_var(keycode);
+       u8 toggle;
 
        deb_info("%s()\n", __func__);
        if (d == NULL)
@@ -506,9 +541,8 @@ static void dib0700_rc_urb_completion(struct urb *purb)
                return;
        }
 
-       keymap = d->props.rc_key_map;
        st = d->priv;
-       buf = (u8 *)purb->transfer_buffer;
+       poll_reply = purb->transfer_buffer;
 
        if (purb->status < 0) {
                deb_info("discontinuing polling\n");
@@ -521,104 +555,52 @@ static void dib0700_rc_urb_completion(struct urb *purb)
                goto resubmit;
        }
 
-       /* Set initial results in case we exit the function early */
-       event = 0;
-       state = REMOTE_NO_KEY_PRESSED;
-
-       deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
-                buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
+       deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
+                poll_reply->report_id, poll_reply->data_state,
+                poll_reply->system, poll_reply->not_system,
+                poll_reply->data, poll_reply->not_data,
+                purb->actual_length);
 
-       switch (dvb_usb_dib0700_ir_proto) {
-       case 0:
-               /* NEC Protocol */
-               poll_reply.report_id  = 0;
-               poll_reply.data_state = 1;
-               poll_reply.system     = buf[2];
-               poll_reply.data       = buf[4];
-               poll_reply.not_data   = buf[5];
+       switch (d->props.rc.core.protocol) {
+       case IR_TYPE_NEC:
+               toggle = 0;
 
                /* NEC protocol sends repeat code as 0 0 0 FF */
-               if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
-                   && (poll_reply.not_data == 0xff)) {
-                       poll_reply.data_state = 2;
+               if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
+                   && (poll_reply->not_data == 0xff)) {
+                       poll_reply->data_state = 2;
                        break;
                }
+
+               if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+                       deb_data("NEC extended protocol\n");
+                       /* NEC extended code - 24 bits */
+                       keycode = poll_reply->system16 << 8 | poll_reply->data;
+               } else {
+                       deb_data("NEC normal protocol\n");
+                       /* normal NEC code - 16 bits */
+                       keycode = poll_reply->system << 8 | poll_reply->data;
+               }
+
                break;
        default:
+               deb_data("RC5 protocol\n");
                /* RC5 Protocol */
-               poll_reply.report_id  = buf[0];
-               poll_reply.data_state = buf[1];
-               poll_reply.system     = (buf[2] << 8) | buf[3];
-               poll_reply.data       = buf[4];
-               poll_reply.not_data   = buf[5];
+               toggle = poll_reply->report_id;
+               keycode = poll_reply->system16 << 8 | poll_reply->data;
+
                break;
        }
 
-       if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+       if ((poll_reply->data + poll_reply->not_data) != 0xff) {
                /* Key failed integrity check */
                err("key failed integrity check: %04x %02x %02x",
-                   poll_reply.system,
-                   poll_reply.data, poll_reply.not_data);
-               goto resubmit;
-       }
-
-       deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
-                poll_reply.report_id, poll_reply.data_state,
-                poll_reply.system, poll_reply.data, poll_reply.not_data);
-
-       /* Find the key in the map */
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
-                   rc5_data(&keymap[i]) == poll_reply.data) {
-                       event = keymap[i].event;
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found == 0) {
-               err("Unknown remote controller key: %04x %02x %02x",
-                   poll_reply.system, poll_reply.data, poll_reply.not_data);
-               d->last_event = 0;
+                   poll_reply->system,
+                   poll_reply->data, poll_reply->not_data);
                goto resubmit;
        }
 
-       if (poll_reply.data_state == 1) {
-               /* New key hit */
-               st->rc_counter = 0;
-               event = keymap[i].event;
-               state = REMOTE_KEY_PRESSED;
-               d->last_event = keymap[i].event;
-       } else if (poll_reply.data_state == 2) {
-               /* Key repeated */
-               st->rc_counter++;
-
-               /* prevents unwanted double hits */
-               if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
-                       event = d->last_event;
-                       state = REMOTE_KEY_PRESSED;
-                       st->rc_counter = RC_REPEAT_DELAY_V1_20;
-               }
-       } else {
-               err("Unknown data state [%d]", poll_reply.data_state);
-       }
-
-       switch (state) {
-       case REMOTE_NO_KEY_PRESSED:
-               break;
-       case REMOTE_KEY_PRESSED:
-               deb_info("key pressed\n");
-               d->last_event = event;
-       case REMOTE_KEY_REPEAT:
-               deb_info("key repeated\n");
-               input_event(d->rc_input_dev, EV_KEY, event, 1);
-               input_sync(d->rc_input_dev);
-               input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
-               input_sync(d->rc_input_dev);
-               break;
-       default:
-               break;
-       }
+       ir_keydown(d->rc_input_dev, keycode, toggle);
 
 resubmit:
        /* Clean the buffer before we requeue */
@@ -631,21 +613,10 @@ resubmit:
 int dib0700_rc_setup(struct dvb_usb_device *d)
 {
        struct dib0700_state *st = d->priv;
-       u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
        struct urb *purb;
        int ret;
-       int i;
-
-       if (d->props.rc_key_map == NULL)
-               return 0;
-
-       /* Set the IR mode */
-       i = dib0700_ctrl_wr(d, rc_setup, 3);
-       if (i<0) {
-               err("ir protocol setup failed");
-               return -1;
-       }
 
+       /* Poll-based. Don't initialize bulk mode */
        if (st->fw_version < 0x10200)
                return 0;
 
@@ -653,14 +624,14 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
        purb = usb_alloc_urb(0, GFP_KERNEL);
        if (purb == NULL) {
                err("rc usb alloc urb failed\n");
-               return -1;
+               return -ENOMEM;
        }
 
        purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
        if (purb->transfer_buffer == NULL) {
                err("rc kzalloc failed\n");
                usb_free_urb(purb);
-               return -1;
+               return -ENOMEM;
        }
 
        purb->status = -EINPROGRESS;
@@ -669,12 +640,10 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
                          dib0700_rc_urb_completion, d);
 
        ret = usb_submit_urb(purb, GFP_ATOMIC);
-       if (ret != 0) {
+       if (ret)
                err("rc submit urb failed\n");
-               return -1;
-       }
 
-       return 0;
+       return ret;
 }
 
 static int dib0700_probe(struct usb_interface *intf,
@@ -698,6 +667,15 @@ static int dib0700_probe(struct usb_interface *intf,
                        st->fw_version = fw_version;
                        st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
 
+                       /* Disable polling mode on newer firmwares */
+                       if (st->fw_version >= 0x10200)
+                               dev->props.rc.core.bulk_mode = true;
+                       else
+                               dev->props.rc.core.bulk_mode = false;
+
+                       /* Need a higher delay, to avoid wrong repeat */
+                       dev->rc_input_dev->rep[REP_DELAY] = 500;
+
                        dib0700_rc_setup(dev);
 
                        return 0;
index 800800a9649e66fae295186d48432d33dae34e12..f634d2e784b2ce24a005b0593372b505b903e1c3 100644 (file)
@@ -473,16 +473,19 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY 6
 
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+/*
+ * This function is used only when firmware is < 1.20 version. Newer
+ * firmwares use bulk mode, with functions implemented at dib0700_core,
+ * at dib0700_rc_urb_completion()
+ */
+static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
 {
        u8 key[4];
+       u32 keycode;
+       u8 toggle;
        int i;
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
        struct dib0700_state *st = d->priv;
 
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
-
        if (st->fw_version >= 0x10200) {
                /* For 1.20 firmware , We need to keep the RC polling
                   callback so we can reuse the input device setup in
@@ -491,348 +494,45 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                return 0;
        }
 
-       i=dib0700_ctrl_rd(d,rc_request,2,key,4);
-       if (i<=0) {
+       i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
+       if (i <= 0) {
                err("RC Query Failed");
                return -1;
        }
 
        /* losing half of KEY_0 events from Philipps rc5 remotes.. */
-       if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+       if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
+               return 0;
 
        /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
 
        dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
 
-       switch (dvb_usb_dib0700_ir_proto) {
-       case 0: {
+       d->last_event = 0;
+       switch (d->props.rc.core.protocol) {
+       case IR_TYPE_NEC:
                /* NEC protocol sends repeat code as 0 0 0 FF */
                if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
-                   (key[3] == 0xFF)) {
-                       st->rc_counter++;
-                       if (st->rc_counter > RC_REPEAT_DELAY) {
-                               *event = d->last_event;
-                               *state = REMOTE_KEY_PRESSED;
-                               st->rc_counter = RC_REPEAT_DELAY;
-                       }
-                       return 0;
-               }
-               for (i=0;i<d->props.rc_key_map_size; i++) {
-                       if (rc5_custom(&keymap[i]) == key[3-2] &&
-                           rc5_data(&keymap[i]) == key[3-3]) {
-                               st->rc_counter = 0;
-                               *event = keymap[i].event;
-                               *state = REMOTE_KEY_PRESSED;
-                               d->last_event = keymap[i].event;
-                               return 0;
-                       }
+                   (key[3] == 0xff))
+                       keycode = d->last_event;
+               else {
+                       keycode = key[3-2] << 8 | key[3-3];
+                       d->last_event = keycode;
                }
+
+               ir_keydown(d->rc_input_dev, keycode, 0);
                break;
-       }
-       default: {
+       default:
                /* RC-5 protocol changes toggle bit on new keypress */
-               for (i = 0; i < d->props.rc_key_map_size; i++) {
-                       if (rc5_custom(&keymap[i]) == key[3-2] &&
-                           rc5_data(&keymap[i]) == key[3-3]) {
-                               if (d->last_event == keymap[i].event &&
-                                       key[3-1] == st->rc_toggle) {
-                                       st->rc_counter++;
-                                       /* prevents unwanted double hits */
-                                       if (st->rc_counter > RC_REPEAT_DELAY) {
-                                               *event = d->last_event;
-                                               *state = REMOTE_KEY_PRESSED;
-                                               st->rc_counter = RC_REPEAT_DELAY;
-                                       }
-
-                                       return 0;
-                               }
-                               st->rc_counter = 0;
-                               *event = keymap[i].event;
-                               *state = REMOTE_KEY_PRESSED;
-                               st->rc_toggle = key[3-1];
-                               d->last_event = keymap[i].event;
-                               return 0;
-                       }
-               }
+               keycode = key[3-2] << 8 | key[3-3];
+               toggle = key[3-1];
+               ir_keydown(d->rc_input_dev, keycode, toggle);
+
                break;
        }
-       }
-       err("Unknown remote controller key: %2X %2X %2X %2X", (int) key[3-2], (int) key[3-3], (int) key[3-1], (int) key[3]);
-       d->last_event = 0;
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_dib0700_table[] = {
-       /* Key codes for the tiny Pinnacle remote*/
-       { 0x0700, KEY_MUTE },
-       { 0x0701, KEY_MENU }, /* Pinnacle logo */
-       { 0x0739, KEY_POWER },
-       { 0x0703, KEY_VOLUMEUP },
-       { 0x0709, KEY_VOLUMEDOWN },
-       { 0x0706, KEY_CHANNELUP },
-       { 0x070c, KEY_CHANNELDOWN },
-       { 0x070f, KEY_1 },
-       { 0x0715, KEY_2 },
-       { 0x0710, KEY_3 },
-       { 0x0718, KEY_4 },
-       { 0x071b, KEY_5 },
-       { 0x071e, KEY_6 },
-       { 0x0711, KEY_7 },
-       { 0x0721, KEY_8 },
-       { 0x0712, KEY_9 },
-       { 0x0727, KEY_0 },
-       { 0x0724, KEY_SCREEN }, /* 'Square' key */
-       { 0x072a, KEY_TEXT },   /* 'T' key */
-       { 0x072d, KEY_REWIND },
-       { 0x0730, KEY_PLAY },
-       { 0x0733, KEY_FASTFORWARD },
-       { 0x0736, KEY_RECORD },
-       { 0x073c, KEY_STOP },
-       { 0x073f, KEY_CANCEL }, /* '?' key */
-       /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
-       { 0xeb01, KEY_POWER },
-       { 0xeb02, KEY_1 },
-       { 0xeb03, KEY_2 },
-       { 0xeb04, KEY_3 },
-       { 0xeb05, KEY_4 },
-       { 0xeb06, KEY_5 },
-       { 0xeb07, KEY_6 },
-       { 0xeb08, KEY_7 },
-       { 0xeb09, KEY_8 },
-       { 0xeb0a, KEY_9 },
-       { 0xeb0b, KEY_VIDEO },
-       { 0xeb0c, KEY_0 },
-       { 0xeb0d, KEY_REFRESH },
-       { 0xeb0f, KEY_EPG },
-       { 0xeb10, KEY_UP },
-       { 0xeb11, KEY_LEFT },
-       { 0xeb12, KEY_OK },
-       { 0xeb13, KEY_RIGHT },
-       { 0xeb14, KEY_DOWN },
-       { 0xeb16, KEY_INFO },
-       { 0xeb17, KEY_RED },
-       { 0xeb18, KEY_GREEN },
-       { 0xeb19, KEY_YELLOW },
-       { 0xeb1a, KEY_BLUE },
-       { 0xeb1b, KEY_CHANNELUP },
-       { 0xeb1c, KEY_VOLUMEUP },
-       { 0xeb1d, KEY_MUTE },
-       { 0xeb1e, KEY_VOLUMEDOWN },
-       { 0xeb1f, KEY_CHANNELDOWN },
-       { 0xeb40, KEY_PAUSE },
-       { 0xeb41, KEY_HOME },
-       { 0xeb42, KEY_MENU }, /* DVD Menu */
-       { 0xeb43, KEY_SUBTITLE },
-       { 0xeb44, KEY_TEXT }, /* Teletext */
-       { 0xeb45, KEY_DELETE },
-       { 0xeb46, KEY_TV },
-       { 0xeb47, KEY_DVD },
-       { 0xeb48, KEY_STOP },
-       { 0xeb49, KEY_VIDEO },
-       { 0xeb4a, KEY_AUDIO }, /* Music */
-       { 0xeb4b, KEY_SCREEN }, /* Pic */
-       { 0xeb4c, KEY_PLAY },
-       { 0xeb4d, KEY_BACK },
-       { 0xeb4e, KEY_REWIND },
-       { 0xeb4f, KEY_FASTFORWARD },
-       { 0xeb54, KEY_PREVIOUS },
-       { 0xeb58, KEY_RECORD },
-       { 0xeb5c, KEY_NEXT },
-
-       /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
-       { 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_KPASTERISK },
-       { 0x1e0b, KEY_RED },
-       { 0x1e0c, KEY_RADIO },
-       { 0x1e0d, KEY_MENU },
-       { 0x1e0e, KEY_GRAVE }, /* # */
-       { 0x1e0f, KEY_MUTE },
-       { 0x1e10, KEY_VOLUMEUP },
-       { 0x1e11, KEY_VOLUMEDOWN },
-       { 0x1e12, KEY_CHANNEL },
-       { 0x1e14, KEY_UP },
-       { 0x1e15, KEY_DOWN },
-       { 0x1e16, KEY_LEFT },
-       { 0x1e17, KEY_RIGHT },
-       { 0x1e18, KEY_VIDEO },
-       { 0x1e19, KEY_AUDIO },
-       { 0x1e1a, KEY_MEDIA },
-       { 0x1e1b, KEY_EPG },
-       { 0x1e1c, KEY_TV },
-       { 0x1e1e, KEY_NEXT },
-       { 0x1e1f, KEY_BACK },
-       { 0x1e20, KEY_CHANNELUP },
-       { 0x1e21, KEY_CHANNELDOWN },
-       { 0x1e24, KEY_LAST }, /* Skip backwards */
-       { 0x1e25, KEY_OK },
-       { 0x1e29, KEY_BLUE},
-       { 0x1e2e, KEY_GREEN },
-       { 0x1e30, KEY_PAUSE },
-       { 0x1e32, KEY_REWIND },
-       { 0x1e34, KEY_FASTFORWARD },
-       { 0x1e35, KEY_PLAY },
-       { 0x1e36, KEY_STOP },
-       { 0x1e37, KEY_RECORD },
-       { 0x1e38, KEY_YELLOW },
-       { 0x1e3b, KEY_GOTO },
-       { 0x1e3d, KEY_POWER },
-
-       /* Key codes for the Leadtek Winfast DTV Dongle */
-       { 0x0042, KEY_POWER },
-       { 0x077c, KEY_TUNER },
-       { 0x0f4e, KEY_PRINT }, /* PREVIEW */
-       { 0x0840, KEY_SCREEN }, /* full screen toggle*/
-       { 0x0f71, KEY_DOT }, /* frequency */
-       { 0x0743, KEY_0 },
-       { 0x0c41, KEY_1 },
-       { 0x0443, KEY_2 },
-       { 0x0b7f, KEY_3 },
-       { 0x0e41, KEY_4 },
-       { 0x0643, KEY_5 },
-       { 0x097f, KEY_6 },
-       { 0x0d7e, KEY_7 },
-       { 0x057c, KEY_8 },
-       { 0x0a40, KEY_9 },
-       { 0x0e4e, KEY_CLEAR },
-       { 0x047c, KEY_CHANNEL }, /* show channel number */
-       { 0x0f41, KEY_LAST }, /* recall */
-       { 0x0342, KEY_MUTE },
-       { 0x064c, KEY_RESERVED }, /* PIP button*/
-       { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
-       { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
-       { 0x0b70, KEY_RECORD },
-       { 0x037d, KEY_VOLUMEUP },
-       { 0x017d, KEY_VOLUMEDOWN },
-       { 0x0242, KEY_CHANNELUP },
-       { 0x007d, KEY_CHANNELDOWN },
-
-       /* Key codes for Nova-TD "credit card" remote control. */
-       { 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_CHANNEL },
-       { 0x1d14, KEY_UP },
-       { 0x1d15, KEY_DOWN },
-       { 0x1d16, KEY_LEFT },
-       { 0x1d17, KEY_RIGHT },
-       { 0x1d1c, KEY_TV },
-       { 0x1d1e, KEY_NEXT },
-       { 0x1d1f, KEY_BACK },
-       { 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 },
-
-       /* Key codes for the Pixelview SBTVD remote (proto NEC) */
-       { 0x8613, KEY_MUTE },
-       { 0x8612, KEY_POWER },
-       { 0x8601, KEY_1 },
-       { 0x8602, KEY_2 },
-       { 0x8603, KEY_3 },
-       { 0x8604, KEY_4 },
-       { 0x8605, KEY_5 },
-       { 0x8606, KEY_6 },
-       { 0x8607, KEY_7 },
-       { 0x8608, KEY_8 },
-       { 0x8609, KEY_9 },
-       { 0x8600, KEY_0 },
-       { 0x860d, KEY_CHANNELUP },
-       { 0x8619, KEY_CHANNELDOWN },
-       { 0x8610, KEY_VOLUMEUP },
-       { 0x860c, KEY_VOLUMEDOWN },
-
-       { 0x860a, KEY_CAMERA },
-       { 0x860b, KEY_ZOOM },
-       { 0x861b, KEY_BACKSPACE },
-       { 0x8615, KEY_ENTER },
-
-       { 0x861d, KEY_UP },
-       { 0x861e, KEY_DOWN },
-       { 0x860e, KEY_LEFT },
-       { 0x860f, KEY_RIGHT },
-
-       { 0x8618, KEY_RECORD },
-       { 0x861a, KEY_STOP },
-
-       /* Key codes for the EvolutePC TVWay+ remote (proto NEC) */
-       { 0x7a00, KEY_MENU },
-       { 0x7a01, KEY_RECORD },
-       { 0x7a02, KEY_PLAY },
-       { 0x7a03, KEY_STOP },
-       { 0x7a10, KEY_CHANNELUP },
-       { 0x7a11, KEY_CHANNELDOWN },
-       { 0x7a12, KEY_VOLUMEUP },
-       { 0x7a13, KEY_VOLUMEDOWN },
-       { 0x7a40, KEY_POWER },
-       { 0x7a41, KEY_MUTE },
-
-       /* Key codes for the Elgato EyeTV Diversity silver remote,
-          set dvb_usb_dib0700_ir_proto=0 */
-       { 0x4501, KEY_POWER },
-       { 0x4502, KEY_MUTE },
-       { 0x4503, KEY_1 },
-       { 0x4504, KEY_2 },
-       { 0x4505, KEY_3 },
-       { 0x4506, KEY_4 },
-       { 0x4507, KEY_5 },
-       { 0x4508, KEY_6 },
-       { 0x4509, KEY_7 },
-       { 0x450a, KEY_8 },
-       { 0x450b, KEY_9 },
-       { 0x450c, KEY_LAST },
-       { 0x450d, KEY_0 },
-       { 0x450e, KEY_ENTER },
-       { 0x450f, KEY_RED },
-       { 0x4510, KEY_CHANNELUP },
-       { 0x4511, KEY_GREEN },
-       { 0x4512, KEY_VOLUMEDOWN },
-       { 0x4513, KEY_OK },
-       { 0x4514, KEY_VOLUMEUP },
-       { 0x4515, KEY_YELLOW },
-       { 0x4516, KEY_CHANNELDOWN },
-       { 0x4517, KEY_BLUE },
-       { 0x4518, KEY_LEFT }, /* Skip backwards */
-       { 0x4519, KEY_PLAYPAUSE },
-       { 0x451a, KEY_RIGHT }, /* Skip forward */
-       { 0x451b, KEY_REWIND },
-       { 0x451c, KEY_L }, /* Live */
-       { 0x451d, KEY_FASTFORWARD },
-       { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
-       { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
-       { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
-       { 0x4541, KEY_SCREEN }, /*  Full screen toggle, 'Hold' for Teletext */
-       { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
-};
-
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
 static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
        BAND_UHF | BAND_VHF,
@@ -2168,10 +1868,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 2,
@@ -2197,10 +1904,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 2,
@@ -2251,11 +1965,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
-
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -2288,10 +2008,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -2358,11 +2086,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
-
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -2397,11 +2132,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
-
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 2,
@@ -2431,7 +2173,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .num_device_descs = 7,
+               .num_device_descs = 6,
                .devices = {
                        {   "DiBcom STK7070PD reference design",
                                { &dib0700_usb_id_table[17], NULL },
@@ -2458,15 +2200,69 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[44], 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,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_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  = stk7070pd_frontend_attach0,
+                               .tuner_attach     = dib7070p_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .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  = stk7070pd_frontend_attach1,
+                               .tuner_attach     = dib7070p_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+                               .size_of_priv     = sizeof(struct dib0700_adapter_state),
+                       }
+               },
+
+               .num_device_descs = 1,
+               .devices = {
                        {   "Elgato EyeTV Diversity",
                                { &dib0700_usb_id_table[68], NULL },
                                { NULL },
                        },
                },
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
                .num_adapters = 1,
@@ -2525,10 +2321,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { NULL },
                        },
                },
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
                .num_adapters = 1,
                .adapter = {
@@ -2554,10 +2359,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { NULL },
                        },
                },
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
                .num_adapters = 1,
                .adapter = {
@@ -2615,10 +2429,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { NULL },
                        },
                },
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
                .num_adapters = 1,
                .adapter = {
@@ -2653,11 +2476,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
-
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
                .num_adapters = 2,
                .adapter = {
@@ -2697,10 +2527,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
                .num_adapters = 1,
                .adapter = {
@@ -2728,10 +2566,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .rc_interval      = DEFAULT_RC_INTERVAL,
-               .rc_key_map       = ir_codes_dib0700_table,
-               .rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-               .rc_query         = dib0700_rc_query
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .rc_props = {
+                               .allowed_protos = IR_TYPE_RC5 |
+                                                 IR_TYPE_RC6 |
+                                                 IR_TYPE_NEC,
+                               .change_protocol = dib0700_change_protocol,
+                       },
+               },
        },
 };
 
index bc08bc0b723c03045962b39790333bc4d5d9a69e..ba991aa21aff4c38f66661ca94ab8adcf0799984 100644 (file)
@@ -327,7 +327,7 @@ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
 /*
  * common remote control stuff
  */
-struct dvb_usb_rc_key ir_codes_dibusb_table[] = {
+struct ir_scancode ir_codes_dibusb_table[] = {
        /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
        { 0x0016, KEY_POWER },
        { 0x0010, KEY_MUTE },
index eb2e6f050fbe7f91d908d9ba40b0b94b96fda7d6..8e3c0d2cce161b235b02fff433a287eca78fe0f4 100644 (file)
@@ -211,10 +211,12 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
 
        .power_ctrl       = dibusb_power_ctrl,
 
-       .rc_interval      = DEFAULT_RC_INTERVAL,
-       .rc_key_map       = ir_codes_dibusb_table,
-       .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-       .rc_query         = dibusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = ir_codes_dibusb_table,
+               .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+               .rc_query         = dibusb_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
@@ -295,10 +297,12 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
        },
        .power_ctrl       = dibusb_power_ctrl,
 
-       .rc_interval      = DEFAULT_RC_INTERVAL,
-       .rc_key_map       = ir_codes_dibusb_table,
-       .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-       .rc_query         = dibusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = ir_codes_dibusb_table,
+               .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+               .rc_query         = dibusb_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
@@ -359,10 +363,12 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
        },
        .power_ctrl       = dibusb2_0_power_ctrl,
 
-       .rc_interval      = DEFAULT_RC_INTERVAL,
-       .rc_key_map       = ir_codes_dibusb_table,
-       .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-       .rc_query         = dibusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = ir_codes_dibusb_table,
+               .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+               .rc_query         = dibusb_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
@@ -416,10 +422,12 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
        },
        .power_ctrl       = dibusb2_0_power_ctrl,
 
-       .rc_interval      = DEFAULT_RC_INTERVAL,
-       .rc_key_map       = ir_codes_dibusb_table,
-       .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-       .rc_query         = dibusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = ir_codes_dibusb_table,
+               .rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+               .rc_query         = dibusb_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
index 588308eb66388c62c1e017873accbd485c4318a8..1cbc41cb4e8fa0489d9e98b6d8ecf099275bab55 100644 (file)
@@ -81,10 +81,12 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
        },
        .power_ctrl       = dibusb2_0_power_ctrl,
 
-       .rc_interval      = DEFAULT_RC_INTERVAL,
-       .rc_key_map       = ir_codes_dibusb_table,
-       .rc_key_map_size  = 111, /* FIXME */
-       .rc_query         = dibusb_rc_query,
+       .rc.legacy = {
+               .rc_interval      = DEFAULT_RC_INTERVAL,
+               .rc_key_map       = ir_codes_dibusb_table,
+               .rc_key_map_size  = 111, /* FIXME */
+               .rc_query         = dibusb_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
index 3d50ac59088f94e2ea7b9d66ed72db2d605a5eba..61a6bf389472e3610ddaede1ea6b3f78e03b7fad 100644 (file)
@@ -124,7 +124,7 @@ extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
 #define DEFAULT_RC_INTERVAL 150
 //#define DEFAULT_RC_INTERVAL 100000
 
-extern struct dvb_usb_rc_key ir_codes_dibusb_table[];
+extern struct ir_scancode ir_codes_dibusb_table[];
 extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
 extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
 
index e826077094fa70b6dfb579b3b28047150e49c9ed..13d006bb19db4ae454da8c5dfdb400a6b1d1429b 100644 (file)
@@ -161,7 +161,7 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_digitv_table[] = {
+static struct ir_scancode ir_codes_digitv_table[] = {
        { 0x5f55, KEY_0 },
        { 0x6f55, KEY_1 },
        { 0x9f55, KEY_2 },
@@ -237,10 +237,10 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        /* if something is inside the buffer, simulate key press */
        if (key[1] != 0)
        {
-                 for (i = 0; i < d->props.rc_key_map_size; i++) {
-                       if (rc5_custom(&d->props.rc_key_map[i]) == key[1] &&
-                           rc5_data(&d->props.rc_key_map[i]) == key[2]) {
-                               *event = d->props.rc_key_map[i].event;
+                 for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+                       if (rc5_custom(&d->props.rc.legacy.rc_key_map[i]) == key[1] &&
+                           rc5_data(&d->props.rc.legacy.rc_key_map[i]) == key[2]) {
+                               *event = d->props.rc.legacy.rc_key_map[i].keycode;
                                *state = REMOTE_KEY_PRESSED;
                                return 0;
                        }
@@ -310,10 +310,12 @@ static struct dvb_usb_device_properties digitv_properties = {
        },
        .identify_state   = digitv_identify_state,
 
-       .rc_interval      = 1000,
-       .rc_key_map       = ir_codes_digitv_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_digitv_table),
-       .rc_query         = digitv_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 1000,
+               .rc_key_map       = ir_codes_digitv_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_digitv_table),
+               .rc_query         = digitv_rc_query,
+       },
 
        .i2c_algo         = &digitv_i2c_algo,
 
index f57e59044d4d956f17de8948d81fcbb1bada3cb1..ca495e07f35c55041d190c3912b4efa447f964a7 100644 (file)
@@ -57,7 +57,7 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
 
 /* remote control */
 /* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct dvb_usb_rc_key ir_codes_dtt200u_table[] = {
+static struct ir_scancode ir_codes_dtt200u_table[] = {
        { 0x8001, KEY_MUTE },
        { 0x8002, KEY_CHANNELDOWN },
        { 0x8003, KEY_VOLUMEDOWN },
@@ -161,10 +161,12 @@ static struct dvb_usb_device_properties dtt200u_properties = {
        },
        .power_ctrl      = dtt200u_power_ctrl,
 
-       .rc_interval     = 300,
-       .rc_key_map      = ir_codes_dtt200u_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-       .rc_query        = dtt200u_rc_query,
+       .rc.legacy = {
+               .rc_interval     = 300,
+               .rc_key_map      = ir_codes_dtt200u_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+               .rc_query        = dtt200u_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
@@ -206,10 +208,12 @@ static struct dvb_usb_device_properties wt220u_properties = {
        },
        .power_ctrl      = dtt200u_power_ctrl,
 
-       .rc_interval     = 300,
-       .rc_key_map      = ir_codes_dtt200u_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-       .rc_query        = dtt200u_rc_query,
+       .rc.legacy = {
+               .rc_interval     = 300,
+               .rc_key_map      = ir_codes_dtt200u_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+               .rc_query        = dtt200u_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
@@ -251,10 +255,12 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
        },
        .power_ctrl      = dtt200u_power_ctrl,
 
-       .rc_interval     = 300,
-       .rc_key_map      = ir_codes_dtt200u_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-       .rc_query        = dtt200u_rc_query,
+       .rc.legacy = {
+               .rc_interval     = 300,
+               .rc_key_map      = ir_codes_dtt200u_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+               .rc_query        = dtt200u_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
@@ -296,10 +302,12 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
        },
        .power_ctrl      = dtt200u_power_ctrl,
 
-       .rc_interval     = 300,
-       .rc_key_map      = ir_codes_dtt200u_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-       .rc_query        = dtt200u_rc_query,
+       .rc.legacy = {
+               .rc_interval     = 300,
+               .rc_key_map      = ir_codes_dtt200u_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+               .rc_query        = dtt200u_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
index b4afe6f8ed1900f22bc26bd00c1f53aef2f73b34..1a774d58d66409ee3596d63b98ab2387b17cc8ef 100644 (file)
 #define USB_PID_AVERMEDIA_A310                         0xa310
 #define USB_PID_AVERMEDIA_A850                         0x850a
 #define USB_PID_AVERMEDIA_A805                         0xa805
+#define USB_PID_AVERMEDIA_A815M                                0x815a
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_CT3650             0x300d
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
index 5d91f70d2d2d786fab7e8a9522fed36738782633..2e3ea0fa28e01768fc4a1291919897b7aa2509c6 100644 (file)
@@ -15,7 +15,7 @@
 
 /* debug */
 int dvb_usb_debug;
-module_param_named(debug,dvb_usb_debug, int, 0644);
+module_param_named(debug, dvb_usb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256  (or-able))." DVB_USB_DEBUG_STATUS);
 
 int dvb_usb_disable_rc_polling;
@@ -29,7 +29,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID
 static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 {
        struct dvb_usb_adapter *adap;
-       int ret,n;
+       int ret, n;
 
        for (n = 0; n < d->props.num_adapters; n++) {
                adap = &d->adapter[n];
@@ -38,7 +38,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 
                memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
 
-/* speed - when running at FULL speed we need a HW PID filter */
+               /* speed - when running at FULL speed we need a HW PID filter */
                if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
                        err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
                        return -ENODEV;
@@ -46,7 +46,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 
                if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
                        (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
-                       info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
+                       info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count);
                        adap->pid_filtering  = 1;
                        adap->max_feed_count = adap->props.pid_filter_count;
                } else {
@@ -64,9 +64,9 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
                }
 
                if (adap->props.size_of_priv > 0) {
-                       adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
+                       adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
                        if (adap->priv == NULL) {
-                               err("no memory for priv for adapter %d.",n);
+                               err("no memory for priv for adapter %d.", n);
                                return -ENOMEM;
                        }
                }
@@ -86,8 +86,8 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
         * sometimes a timeout occures, this helps
         */
        if (d->props.generic_bulk_ctrl_endpoint != 0) {
-               usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
-               usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+               usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+               usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
        }
 
        return 0;
@@ -96,6 +96,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
 {
        int n;
+
        for (n = 0; n < d->num_adapters_initialized; n++) {
                dvb_usb_adapter_frontend_exit(&d->adapter[n]);
                dvb_usb_adapter_dvb_exit(&d->adapter[n]);
@@ -111,11 +112,11 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
 /* general initialization functions */
 static int dvb_usb_exit(struct dvb_usb_device *d)
 {
-       deb_info("state before exiting everything: %x\n",d->state);
+       deb_info("state before exiting everything: %x\n", d->state);
        dvb_usb_remote_exit(d);
        dvb_usb_adapter_exit(d);
        dvb_usb_i2c_exit(d);
-       deb_info("state should be zero now: %x\n",d->state);
+       deb_info("state should be zero now: %x\n", d->state);
        d->state = DVB_USB_STATE_INIT;
        kfree(d->priv);
        kfree(d);
@@ -132,14 +133,14 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
        d->state = DVB_USB_STATE_INIT;
 
        if (d->props.size_of_priv > 0) {
-               d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
+               d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
                if (d->priv == NULL) {
                        err("no memory for priv in 'struct dvb_usb_device'");
                        return -ENOMEM;
                }
        }
 
-/* check the capabilities and set appropriate variables */
+       /* check the capabilities and set appropriate variables */
        dvb_usb_device_power_ctrl(d, 1);
 
        if ((ret = dvb_usb_i2c_init(d)) ||
@@ -157,16 +158,17 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
 }
 
 /* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
+static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
 {
-       int i,j;
+       int i, j;
        struct dvb_usb_device_description *desc = NULL;
+
        *cold = -1;
 
        for (i = 0; i < props->num_device_descs; i++) {
 
                for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
-                       deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+                       deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
                        if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
                                props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
                                *cold = 1;
@@ -179,7 +181,7 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
                        break;
 
                for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
-                       deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+                       deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
                        if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
                                props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
                                *cold = 0;
@@ -190,7 +192,7 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
        }
 
        if (desc != NULL && props->identify_state != NULL)
-               props->identify_state(udev,props,&desc,cold);
+               props->identify_state(udev, props, &desc, cold);
 
        return desc;
 }
@@ -202,7 +204,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
        else
                d->powered--;
 
-       if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
+       if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
                deb_info("power control: %d\n", onoff);
                if (d->props.power_ctrl)
                        return d->props.power_ctrl(d, onoff);
@@ -222,32 +224,32 @@ int dvb_usb_device_init(struct usb_interface *intf,
        struct dvb_usb_device *d = NULL;
        struct dvb_usb_device_description *desc = NULL;
 
-       int ret = -ENOMEM,cold=0;
+       int ret = -ENOMEM, cold = 0;
 
        if (du != NULL)
                *du = NULL;
 
-       if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
+       if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
                deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
                return -ENODEV;
        }
 
        if (cold) {
-               info("found a '%s' in cold state, will try to load a firmware",desc->name);
-               ret = dvb_usb_download_firmware(udev,props);
+               info("found a '%s' in cold state, will try to load a firmware", desc->name);
+               ret = dvb_usb_download_firmware(udev, props);
                if (!props->no_reconnect || ret != 0)
                        return ret;
        }
 
-       info("found a '%s' in warm state.",desc->name);
-               d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+       info("found a '%s' in warm state.", desc->name);
+       d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
        if (d == NULL) {
                err("no memory for 'struct dvb_usb_device'");
                return -ENOMEM;
        }
 
        d->udev = udev;
-       memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
+       memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
        d->desc = desc;
        d->owner = owner;
 
@@ -259,9 +261,9 @@ int dvb_usb_device_init(struct usb_interface *intf,
        ret = dvb_usb_init(d, adapter_nums);
 
        if (ret == 0)
-               info("%s successfully initialized and connected.",desc->name);
+               info("%s successfully initialized and connected.", desc->name);
        else
-               info("%s error while loading driver (%d)",desc->name,ret);
+               info("%s error while loading driver (%d)", desc->name, ret);
        return ret;
 }
 EXPORT_SYMBOL(dvb_usb_device_init);
@@ -271,12 +273,12 @@ void dvb_usb_device_exit(struct usb_interface *intf)
        struct dvb_usb_device *d = usb_get_intfdata(intf);
        const char *name = "generic DVB-USB module";
 
-       usb_set_intfdata(intf,NULL);
+       usb_set_intfdata(intf, NULL);
        if (d != NULL && d->desc != NULL) {
                name = d->desc->name;
                dvb_usb_exit(d);
        }
-       info("%s successfully deinitialized and disconnected.",name);
+       info("%s successfully deinitialized and disconnected.", name);
 
 }
 EXPORT_SYMBOL(dvb_usb_device_exit);
index 852fe89539cfdb538cbe67b2b3b7cba940d72153..b579fed3ab3f56b6c5614a9d657bfb1a1db023e7 100644 (file)
@@ -8,29 +8,29 @@
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
 
-static int dvb_usb_getkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
                                unsigned int scancode, unsigned int *keycode)
 {
        struct dvb_usb_device *d = input_get_drvdata(dev);
 
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        int i;
 
        /* See if we can match the raw key code. */
-       for (i = 0; i < d->props.rc_key_map_size; i++)
-               if (keymap[i].scan == scancode) {
-                       *keycode = keymap[i].event;
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+               if (keymap[i].scancode == scancode) {
+                       *keycode = keymap[i].keycode;
                        return 0;
                }
 
        /*
         * If is there extra space, returns KEY_RESERVED,
-        * otherwise, input core won't let dvb_usb_setkeycode
+        * otherwise, input core won't let legacy_dvb_usb_setkeycode
         * to work
         */
-       for (i = 0; i < d->props.rc_key_map_size; i++)
-               if (keymap[i].event == KEY_RESERVED ||
-                   keymap[i].event == KEY_UNKNOWN) {
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+               if (keymap[i].keycode == KEY_RESERVED ||
+                   keymap[i].keycode == KEY_UNKNOWN) {
                        *keycode = KEY_RESERVED;
                        return 0;
                }
@@ -38,27 +38,27 @@ static int dvb_usb_getkeycode(struct input_dev *dev,
        return -EINVAL;
 }
 
-static int dvb_usb_setkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
                                unsigned int scancode, unsigned int keycode)
 {
        struct dvb_usb_device *d = input_get_drvdata(dev);
 
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        int i;
 
        /* Search if it is replacing an existing keycode */
-       for (i = 0; i < d->props.rc_key_map_size; i++)
-               if (keymap[i].scan == scancode) {
-                       keymap[i].event = keycode;
+       for (i = 0; i < d->props.rc.legacy.rc_key_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_key_map_size; i++)
-               if (keymap[i].event == KEY_RESERVED ||
-                   keymap[i].event == KEY_UNKNOWN) {
-                       keymap[i].scan = scancode;
-                       keymap[i].event = keycode;
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+               if (keymap[i].keycode == KEY_RESERVED ||
+                   keymap[i].keycode == KEY_UNKNOWN) {
+                       keymap[i].scancode = scancode;
+                       keymap[i].keycode = keycode;
                        return 0;
                }
 
@@ -78,7 +78,7 @@ static int dvb_usb_setkeycode(struct input_dev *dev,
  *
  * TODO: Fix the repeat rate of the input device.
  */
-static void dvb_usb_read_remote_control(struct work_struct *work)
+static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
 {
        struct dvb_usb_device *d =
                container_of(work, struct dvb_usb_device, rc_query_work.work);
@@ -92,7 +92,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
        if (dvb_usb_disable_rc_polling)
                return;
 
-       if (d->props.rc_query(d,&event,&state)) {
+       if (d->props.rc.legacy.rc_query(d,&event,&state)) {
                err("error while querying for an remote control event.");
                goto schedule;
        }
@@ -151,18 +151,117 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
 */
 
 schedule:
-       schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+       schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
+}
+
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d,
+                                     struct input_dev *input_dev)
+{
+       int i, err, rc_interval;
+
+       input_dev->getkeycode = legacy_dvb_usb_getkeycode;
+       input_dev->setkeycode = legacy_dvb_usb_setkeycode;
+
+       /* set the bits for the keys */
+       deb_rc("key map size: %d\n", d->props.rc.legacy.rc_key_map_size);
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+               deb_rc("setting bit for event %d item %d\n",
+                       d->props.rc.legacy.rc_key_map[i].keycode, i);
+               set_bit(d->props.rc.legacy.rc_key_map[i].keycode, input_dev->keybit);
+       }
+
+       /* setting these two values to non-zero, we have to manage key repeats */
+       input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
+       input_dev->rep[REP_DELAY]  = d->props.rc.legacy.rc_interval + 150;
+
+       input_set_drvdata(input_dev, d);
+
+       err = input_register_device(input_dev);
+       if (err)
+               input_free_device(input_dev);
+
+       rc_interval = d->props.rc.legacy.rc_interval;
+
+       INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
+
+       info("schedule remote query interval to %d msecs.", rc_interval);
+       schedule_delayed_work(&d->rc_query_work,
+                             msecs_to_jiffies(rc_interval));
+
+       d->state |= DVB_USB_STATE_REMOTE;
+
+       return err;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+       struct dvb_usb_device *d =
+               container_of(work, struct dvb_usb_device, rc_query_work.work);
+       int err;
+
+       /* TODO: need a lock here.  We can simply skip checking for the remote control
+          if we're busy. */
+
+       /* when the parameter has been set to 1 via sysfs while the
+        * driver was running, or when bulk mode is enabled after IR init
+        */
+       if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
+               return;
+
+       err = d->props.rc.core.rc_query(d);
+       if (err)
+               err("error %d while querying for an remote control event.", err);
+
+       schedule_delayed_work(&d->rc_query_work,
+                             msecs_to_jiffies(d->props.rc.core.rc_interval));
+}
+
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d,
+                                      struct input_dev *input_dev)
+{
+       int err, rc_interval;
+
+       d->props.rc.core.rc_props.priv = d;
+       err = ir_input_register(input_dev,
+                                d->props.rc.core.rc_codes,
+                                &d->props.rc.core.rc_props,
+                                d->props.rc.core.module_name);
+       if (err < 0)
+               return err;
+
+       if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
+               return 0;
+
+       /* Polling mode - initialize a work queue for handling it */
+       INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
+
+       rc_interval = d->props.rc.core.rc_interval;
+
+       info("schedule remote query interval to %d msecs.", rc_interval);
+       schedule_delayed_work(&d->rc_query_work,
+                             msecs_to_jiffies(rc_interval));
+
+       return 0;
 }
 
 int dvb_usb_remote_init(struct dvb_usb_device *d)
 {
        struct input_dev *input_dev;
-       int i;
        int err;
 
-       if (d->props.rc_key_map == NULL ||
-               d->props.rc_query == NULL ||
-               dvb_usb_disable_rc_polling)
+       if (dvb_usb_disable_rc_polling)
+               return 0;
+
+       if (d->props.rc.legacy.rc_key_map && d->props.rc.legacy.rc_query)
+               d->props.rc.mode = DVB_RC_LEGACY;
+       else if (d->props.rc.core.rc_codes)
+               d->props.rc.mode = DVB_RC_CORE;
+       else
                return 0;
 
        usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
@@ -177,39 +276,19 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
        input_dev->phys = d->rc_phys;
        usb_to_input_id(d->udev, &input_dev->id);
        input_dev->dev.parent = &d->udev->dev;
-       input_dev->getkeycode = dvb_usb_getkeycode;
-       input_dev->setkeycode = dvb_usb_setkeycode;
-
-       /* set the bits for the keys */
-       deb_rc("key map size: %d\n", d->props.rc_key_map_size);
-       for (i = 0; i < d->props.rc_key_map_size; i++) {
-               deb_rc("setting bit for event %d item %d\n",
-                       d->props.rc_key_map[i].event, i);
-               set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
-       }
 
        /* Start the remote-control polling. */
-       if (d->props.rc_interval < 40)
-               d->props.rc_interval = 100; /* default */
-
-       /* setting these two values to non-zero, we have to manage key repeats */
-       input_dev->rep[REP_PERIOD] = d->props.rc_interval;
-       input_dev->rep[REP_DELAY]  = d->props.rc_interval + 150;
-
-       input_set_drvdata(input_dev, d);
-
-       err = input_register_device(input_dev);
-       if (err) {
-               input_free_device(input_dev);
-               return err;
-       }
+       if (d->props.rc.legacy.rc_interval < 40)
+               d->props.rc.legacy.rc_interval = 100; /* default */
 
        d->rc_input_dev = input_dev;
 
-       INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
-
-       info("schedule remote query interval to %d msecs.", d->props.rc_interval);
-       schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+       if (d->props.rc.mode == DVB_RC_LEGACY)
+               err = legacy_dvb_usb_remote_init(d, input_dev);
+       else
+               err = rc_core_dvb_usb_remote_init(d, input_dev);
+       if (err)
+               return err;
 
        d->state |= DVB_USB_STATE_REMOTE;
 
@@ -221,7 +300,10 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d)
        if (d->state & DVB_USB_STATE_REMOTE) {
                cancel_rearming_delayed_work(&d->rc_query_work);
                flush_scheduled_work();
-               input_unregister_device(d->rc_input_dev);
+               if (d->props.rc.mode == DVB_RC_LEGACY)
+                       input_unregister_device(d->rc_input_dev);
+               else
+                       ir_input_unregister(d->rc_input_dev);
        }
        d->state &= ~DVB_USB_STATE_REMOTE;
        return 0;
@@ -234,7 +316,7 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
                u8 keybuf[5], u32 *event, int *state)
 {
        int i;
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
        *event = 0;
        *state = REMOTE_NO_KEY_PRESSED;
        switch (keybuf[0]) {
@@ -247,10 +329,10 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
                                break;
                        }
                        /* See if we can match the raw key code. */
-                       for (i = 0; i < d->props.rc_key_map_size; i++)
+                       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
                                if (rc5_custom(&keymap[i]) == keybuf[1] &&
                                        rc5_data(&keymap[i]) == keybuf[3]) {
-                                       *event = keymap[i].event;
+                                       *event = keymap[i].keycode;
                                        *state = REMOTE_KEY_PRESSED;
                                        return 0;
                                }
index 4a9f676087bff9e41740db3cde331db4fbe7d05b..34f7b3ba8cc75f70607d0dc3bf4eaa287cd8ec17 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/usb.h>
 #include <linux/firmware.h>
 #include <linux/mutex.h>
+#include <media/ir-core.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -74,30 +75,19 @@ struct dvb_usb_device_description {
        struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
 };
 
-/**
- * struct dvb_usb_rc_key - a remote control key and its input-event
- * @custom: the vendor/custom part of the key
- * @data: the actual key part
- * @event: the input event assigned to key identified by custom and data
- */
-struct dvb_usb_rc_key {
-       u16 scan;
-       u32 event;
-};
-
-static inline u8 rc5_custom(struct dvb_usb_rc_key *key)
+static inline u8 rc5_custom(struct ir_scancode *key)
 {
-       return (key->scan >> 8) & 0xff;
+       return (key->scancode >> 8) & 0xff;
 }
 
-static inline u8 rc5_data(struct dvb_usb_rc_key *key)
+static inline u8 rc5_data(struct ir_scancode *key)
 {
-       return key->scan & 0xff;
+       return key->scancode & 0xff;
 }
 
-static inline u8 rc5_scan(struct dvb_usb_rc_key *key)
+static inline u8 rc5_scan(struct ir_scancode *key)
 {
-       return key->scan & 0xffff;
+       return key->scancode & 0xffff;
 }
 
 struct dvb_usb_device;
@@ -167,6 +157,55 @@ struct dvb_usb_adapter_properties {
                                  unsigned int, void *, unsigned int);
 };
 
+/**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_key_map: a hard-wired array of struct ir_scancode (NULL to disable
+ *  remote control handling).
+ * @rc_key_map_size: number of items in @rc_key_map.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED      0x00
+#define REMOTE_KEY_PRESSED         0x01
+#define REMOTE_KEY_REPEAT          0x02
+       struct ir_scancode  *rc_key_map;
+       int rc_key_map_size;
+       int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+       int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @rc_props: remote controller properties
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+       char *rc_codes;
+       u64 protocol;
+       char *module_name;
+       int (*rc_query) (struct dvb_usb_device *d);
+       int rc_interval;
+       struct ir_dev_props rc_props;
+       bool bulk_mode;                         /* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ *                    based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+       DVB_RC_LEGACY,
+       DVB_RC_CORE,
+};
+
 /**
  * struct dvb_usb_device_properties - properties of a dvb-usb-device
  * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
@@ -185,11 +224,7 @@ struct dvb_usb_adapter_properties {
  * @identify_state: called to determine the state (cold or warm), when it
  *  is not distinguishable by the USB IDs.
  *
- * @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
- *  remote control handling).
- * @rc_key_map_size: number of items in @rc_key_map.
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
+ * @rc: remote controller properties
  *
  * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
  *
@@ -233,14 +268,11 @@ struct dvb_usb_device_properties {
        int (*identify_state)   (struct usb_device *, struct dvb_usb_device_properties *,
                        struct dvb_usb_device_description **, int *);
 
-/* remote control properties */
-#define REMOTE_NO_KEY_PRESSED      0x00
-#define REMOTE_KEY_PRESSED         0x01
-#define REMOTE_KEY_REPEAT          0x02
-       struct dvb_usb_rc_key  *rc_key_map;
-       int rc_key_map_size;
-       int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
-       int rc_interval;
+       struct {
+               enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */
+               struct dvb_rc_legacy legacy;
+               struct dvb_rc core;
+       } rc;
 
        struct i2c_algorithm *i2c_algo;
 
index e8fb853806722b2db8b440251909cb4965695ae0..774df88dc6e349f524569faa6ce7df0c7dbef447 100644 (file)
@@ -74,7 +74,7 @@
                "on firmware-problems."
 
 struct ir_codes_dvb_usb_table_table {
-       struct dvb_usb_rc_key *rc_keys;
+       struct ir_scancode *rc_keys;
        int rc_keys_size;
 };
 
@@ -948,7 +948,7 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
+static struct ir_scancode ir_codes_dw210x_table[] = {
        { 0xf80a, KEY_Q },              /*power*/
        { 0xf80c, KEY_M },              /*mute*/
        { 0xf811, KEY_1 },
@@ -982,7 +982,7 @@ static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
        { 0xf81b, KEY_B },              /*recall*/
 };
 
-static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
+static struct ir_scancode ir_codes_tevii_table[] = {
        { 0xf80a, KEY_POWER },
        { 0xf80c, KEY_MUTE },
        { 0xf811, KEY_1 },
@@ -1032,7 +1032,7 @@ static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
        { 0xf858, KEY_SWITCHVIDEOMODE },
 };
 
-static struct dvb_usb_rc_key ir_codes_tbs_table[] = {
+static struct ir_scancode ir_codes_tbs_table[] = {
        { 0xf884, KEY_POWER },
        { 0xf894, KEY_MUTE },
        { 0xf887, KEY_1 },
@@ -1075,8 +1075,8 @@ static struct ir_codes_dvb_usb_table_table keys_tables[] = {
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
-       int keymap_size = d->props.rc_key_map_size;
+       struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+       int keymap_size = d->props.rc.legacy.rc_key_map_size;
        u8 key[2];
        struct i2c_msg msg = {
                .addr = DW2102_RC_QUERY,
@@ -1096,7 +1096,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                for (i = 0; i < keymap_size ; i++) {
                        if (rc5_data(&keymap[i]) == msg.buf[0]) {
                                *state = REMOTE_KEY_PRESSED;
-                               *event = keymap[i].event;
+                               *event = keymap[i].keycode;
                                break;
                        }
 
@@ -1185,13 +1185,13 @@ static int dw2102_load_firmware(struct usb_device *dev,
                /* init registers */
                switch (dev->descriptor.idProduct) {
                case USB_PID_PROF_1100:
-                       s6x0_properties.rc_key_map = ir_codes_tbs_table;
-                       s6x0_properties.rc_key_map_size =
+                       s6x0_properties.rc.legacy.rc_key_map = ir_codes_tbs_table;
+                       s6x0_properties.rc.legacy.rc_key_map_size =
                                        ARRAY_SIZE(ir_codes_tbs_table);
                        break;
                case USB_PID_TEVII_S650:
-                       dw2104_properties.rc_key_map = ir_codes_tevii_table;
-                       dw2104_properties.rc_key_map_size =
+                       dw2104_properties.rc.legacy.rc_key_map = ir_codes_tevii_table;
+                       dw2104_properties.rc.legacy.rc_key_map_size =
                                        ARRAY_SIZE(ir_codes_tevii_table);
                case USB_PID_DW2104:
                        reset = 1;
@@ -1255,10 +1255,13 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &dw2102_serit_i2c_algo,
-       .rc_key_map = ir_codes_dw210x_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
-       .rc_interval = 150,
-       .rc_query = dw2102_rc_query,
+
+       .rc.legacy = {
+               .rc_key_map = ir_codes_dw210x_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+               .rc_interval = 150,
+               .rc_query = dw2102_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x81,
        /* parameter for the MPEG2-data transfer */
@@ -1306,10 +1309,12 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &dw2104_i2c_algo,
-       .rc_key_map = ir_codes_dw210x_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
-       .rc_interval = 150,
-       .rc_query = dw2102_rc_query,
+       .rc.legacy = {
+               .rc_key_map = ir_codes_dw210x_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+               .rc_interval = 150,
+               .rc_query = dw2102_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x81,
        /* parameter for the MPEG2-data transfer */
@@ -1353,10 +1358,12 @@ static struct dvb_usb_device_properties dw3101_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &dw3101_i2c_algo,
-       .rc_key_map = ir_codes_dw210x_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
-       .rc_interval = 150,
-       .rc_query = dw2102_rc_query,
+       .rc.legacy = {
+               .rc_key_map = ir_codes_dw210x_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+               .rc_interval = 150,
+               .rc_query = dw2102_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x81,
        /* parameter for the MPEG2-data transfer */
@@ -1396,10 +1403,12 @@ static struct dvb_usb_device_properties s6x0_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &s6x0_i2c_algo,
-       .rc_key_map = ir_codes_tevii_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
-       .rc_interval = 150,
-       .rc_query = dw2102_rc_query,
+       .rc.legacy = {
+               .rc_key_map = ir_codes_tevii_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
+               .rc_interval = 150,
+               .rc_query = dw2102_rc_query,
+       },
 
        .generic_bulk_ctrl_endpoint = 0x81,
        .num_adapters = 1,
@@ -1459,8 +1468,8 @@ static int dw2102_probe(struct usb_interface *intf,
        /* fill only different fields */
        p7500->firmware = "dvb-usb-p7500.fw";
        p7500->devices[0] = d7500;
-       p7500->rc_key_map = ir_codes_tbs_table;
-       p7500->rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
+       p7500->rc.legacy.rc_key_map = ir_codes_tbs_table;
+       p7500->rc.legacy.rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
        p7500->adapter->frontend_attach = prof_7500_frontend_attach;
 
        if (0 == dvb_usb_device_init(intf, &dw2102_properties,
index 7a7f1b2b681ccaa38fbc9161aa8b0d726f14952b..dbdb5347b2a8b1c1983cfdc8bbfeb307caa862c2 100644 (file)
@@ -349,7 +349,7 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
                         * FE_CAN_QAM_16 is for compatibility
                         * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
                         */
-                       FE_CAN_QPSK | FE_CAN_QAM_16
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
        },
 
        .release = gp8psk_fe_release,
index c211fef45fc342dd0d4ac7a3484fab1ce21150a8..bdef1a18b664ea22c854646788708c4468b1327b 100644 (file)
@@ -69,7 +69,7 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
        int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
 
        /* Remote controller init. */
-       if (d->props.rc_query) {
+       if (d->props.rc.legacy.rc_query) {
                deb("Initialising remote control\n");
                while (rc_seq->address) {
                        if ((ret = m920x_write(d->udev, M9206_CORE,
@@ -142,9 +142,9 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
                goto unlock;
 
-       for (i = 0; i < d->props.rc_key_map_size; i++)
-               if (rc5_data(&d->props.rc_key_map[i]) == rc_state[1]) {
-                       *event = d->props.rc_key_map[i].event;
+       for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+               if (rc5_data(&d->props.rc.legacy.rc_key_map[i]) == rc_state[1]) {
+                       *event = d->props.rc.legacy.rc_key_map[i].keycode;
 
                        switch(rc_state[0]) {
                        case 0x80:
@@ -589,7 +589,7 @@ static struct m920x_inits pinnacle310e_init[] = {
 };
 
 /* ir keymaps */
-static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
+static struct ir_scancode ir_codes_megasky_table[] = {
        { 0x0012, KEY_POWER },
        { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
        { 0x0002, KEY_CHANNELUP },
@@ -608,7 +608,7 @@ static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
        { 0x000e, KEY_COFFEE }, /* "MTS" */
 };
 
-static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
+static struct ir_scancode ir_codes_tvwalkertwin_table[] = {
        { 0x0001, KEY_ZOOM }, /* Full Screen */
        { 0x0002, KEY_CAMERA }, /* snapshot */
        { 0x0003, KEY_MUTE },
@@ -628,7 +628,7 @@ static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
        { 0x001e, KEY_VOLUMEUP },
 };
 
-static struct dvb_usb_rc_key ir_codes_pinnacle310e_table[] = {
+static struct ir_scancode ir_codes_pinnacle310e_table[] = {
        { 0x16, KEY_POWER },
        { 0x17, KEY_FAVORITES },
        { 0x0f, KEY_TEXT },
@@ -784,10 +784,12 @@ static struct dvb_usb_device_properties megasky_properties = {
        .firmware = "dvb-usb-megasky-02.fw",
        .download_firmware = m920x_firmware_download,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_megasky_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_megasky_table),
-       .rc_query         = m920x_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_megasky_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_megasky_table),
+               .rc_query         = m920x_rc_query,
+       },
 
        .size_of_priv     = sizeof(struct m920x_state),
 
@@ -885,10 +887,12 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
        .firmware = "dvb-usb-tvwalkert.fw",
        .download_firmware = m920x_firmware_download,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_tvwalkertwin_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
-       .rc_query         = m920x_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_tvwalkertwin_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
+               .rc_query         = m920x_rc_query,
+       },
 
        .size_of_priv     = sizeof(struct m920x_state),
 
@@ -992,10 +996,12 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
        .usb_ctrl = DEVICE_SPECIFIC,
        .download_firmware = NULL,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_pinnacle310e_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_pinnacle310e_table),
-       .rc_query         = m920x_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_pinnacle310e_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_pinnacle310e_table),
+               .rc_query         = m920x_rc_query,
+       },
 
        .size_of_priv     = sizeof(struct m920x_state),
 
index d195a587cc651ac5f3b25bbadd8306cd4ba42d6c..181f36a12e2ad12b02b8a6a0e058ecf50aadc388 100644 (file)
@@ -21,7 +21,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 #define deb_ee(args...) dprintk(debug,0x02,args)
 
 /* Hauppauge NOVA-T USB2 keys */
-static struct dvb_usb_rc_key ir_codes_haupp_table [] = {
+static struct ir_scancode ir_codes_haupp_table[] = {
        { 0x1e00, KEY_0 },
        { 0x1e01, KEY_1 },
        { 0x1e02, KEY_2 },
@@ -98,7 +98,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                                        deb_rc("c: %x, d: %x\n", rc5_data(&ir_codes_haupp_table[i]),
                                                                 rc5_custom(&ir_codes_haupp_table[i]));
 
-                                       *event = ir_codes_haupp_table[i].event;
+                                       *event = ir_codes_haupp_table[i].keycode;
                                        *state = REMOTE_KEY_PRESSED;
                                        if (st->old_toggle == toggle) {
                                                if (st->last_repeat_count++ < 2)
@@ -195,10 +195,12 @@ static struct dvb_usb_device_properties nova_t_properties = {
        .power_ctrl       = dibusb2_0_power_ctrl,
        .read_mac_address = nova_t_read_mac_address,
 
-       .rc_interval      = 100,
-       .rc_key_map       = ir_codes_haupp_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_haupp_table),
-       .rc_query         = nova_t_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 100,
+               .rc_key_map       = ir_codes_haupp_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_haupp_table),
+               .rc_query         = nova_t_rc_query,
+       },
 
        .i2c_algo         = &dibusb_i2c_algo,
 
index dfb81ff1d9a7735cac3a118ba702eb69383299ba..6b22ec64ab0cc69d7124bc16421309d3e9c070cd 100644 (file)
@@ -331,7 +331,7 @@ static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
        return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_opera1_table[] = {
+static struct ir_scancode ir_codes_opera1_table[] = {
        {0x5fa0, KEY_1},
        {0x51af, KEY_2},
        {0x5da2, KEY_3},
@@ -407,9 +407,9 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
                for (i = 0; i < ARRAY_SIZE(ir_codes_opera1_table); i++) {
                        if (rc5_scan(&ir_codes_opera1_table[i]) == (send_key & 0xffff)) {
                                *state = REMOTE_KEY_PRESSED;
-                               *event = ir_codes_opera1_table[i].event;
+                               *event = ir_codes_opera1_table[i].keycode;
                                opst->last_key_pressed =
-                                       ir_codes_opera1_table[i].event;
+                                       ir_codes_opera1_table[i].keycode;
                                break;
                        }
                        opst->last_key_pressed = 0;
@@ -498,10 +498,12 @@ static struct dvb_usb_device_properties opera1_properties = {
        .power_ctrl = opera1_power_ctrl,
        .i2c_algo = &opera1_i2c_algo,
 
-       .rc_key_map = ir_codes_opera1_table,
-       .rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
-       .rc_interval = 200,
-       .rc_query = opera1_rc_query,
+       .rc.legacy = {
+               .rc_key_map = ir_codes_opera1_table,
+               .rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
+               .rc_interval = 200,
+               .rc_query = opera1_rc_query,
+       },
        .read_mac_address = opera1_read_mac_address,
        .generic_bulk_ctrl_endpoint = 0x00,
        /* parameter for the MPEG2-data transfer */
index 4d332451653b1e451513b9e6b7342b22830e8fd7..5c9f3275aaa0f3fac30117c3a56f1f873c30d5c7 100644 (file)
@@ -174,7 +174,7 @@ static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_vp702x_table[] = {
+static struct ir_scancode ir_codes_vp702x_table[] = {
        { 0x0001, KEY_1 },
        { 0x0002, KEY_2 },
 };
@@ -200,7 +200,7 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        for (i = 0; i < ARRAY_SIZE(ir_codes_vp702x_table); i++)
                if (rc5_custom(&ir_codes_vp702x_table[i]) == key[1]) {
                        *state = REMOTE_KEY_PRESSED;
-                       *event = ir_codes_vp702x_table[i].event;
+                       *event = ir_codes_vp702x_table[i].keycode;
                        break;
                }
        return 0;
@@ -283,10 +283,12 @@ static struct dvb_usb_device_properties vp702x_properties = {
        },
        .read_mac_address = vp702x_read_mac_addr,
 
-       .rc_key_map       = ir_codes_vp702x_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_vp702x_table),
-       .rc_interval      = 400,
-       .rc_query         = vp702x_rc_query,
+       .rc.legacy = {
+               .rc_key_map       = ir_codes_vp702x_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_vp702x_table),
+               .rc_interval      = 400,
+               .rc_query         = vp702x_rc_query,
+       },
 
        .num_device_descs = 1,
        .devices = {
index 036893fa4480b5518aed3aa5dafa7aa2fa29c39b..f13791ca59945a7f8b18f73dc88329faab524de7 100644 (file)
@@ -99,7 +99,7 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
 
 /* The keymapping struct. Somehow this should be loaded to the driver, but
  * currently it is hardcoded. */
-static struct dvb_usb_rc_key ir_codes_vp7045_table[] = {
+static struct ir_scancode ir_codes_vp7045_table[] = {
        { 0x0016, KEY_POWER },
        { 0x0010, KEY_MUTE },
        { 0x0003, KEY_1 },
@@ -168,7 +168,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        for (i = 0; i < ARRAY_SIZE(ir_codes_vp7045_table); i++)
                if (rc5_data(&ir_codes_vp7045_table[i]) == key) {
                        *state = REMOTE_KEY_PRESSED;
-                       *event = ir_codes_vp7045_table[i].event;
+                       *event = ir_codes_vp7045_table[i].keycode;
                        break;
                }
        return 0;
@@ -259,10 +259,12 @@ static struct dvb_usb_device_properties vp7045_properties = {
        .power_ctrl       = vp7045_power_ctrl,
        .read_mac_address = vp7045_read_mac_addr,
 
-       .rc_interval      = 400,
-       .rc_key_map       = ir_codes_vp7045_table,
-       .rc_key_map_size  = ARRAY_SIZE(ir_codes_vp7045_table),
-       .rc_query         = vp7045_rc_query,
+       .rc.legacy = {
+               .rc_interval      = 400,
+               .rc_key_map       = ir_codes_vp7045_table,
+               .rc_key_map_size  = ARRAY_SIZE(ir_codes_vp7045_table),
+               .rc_query         = vp7045_rc_query,
+       },
 
        .num_device_descs = 2,
        .devices = {
index cd7f9b7cbffabad65972ca372b03e6830c19b7a4..51d578a758a7cc90a4ef624d79277826071977a0 100644 (file)
@@ -584,6 +584,7 @@ config DVB_LGS8GL5
 config DVB_LGS8GXX
        tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
        depends on DVB_CORE && I2C
+       select FW_LOADER
        default m if DVB_FE_CUSTOMISE
        help
          A DMB-TH tuner module. Say Y when you want to support this frontend.
index 12e018b4107daec6758c7571ef3bb3bd4e244159..dac917f7bb7f8b79f6939a60aa1f43b40c580656 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
  *
@@ -761,6 +761,10 @@ static int af9013_set_frontend(struct dvb_frontend *fe,
 
        state->frequency = params->frequency;
 
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, params);
+
        /* program CFOE coefficients */
        ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
        if (ret)
@@ -791,10 +795,6 @@ static int af9013_set_frontend(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
-       /* program tuner */
-       if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, params);
-
        /* program TPS and bandwidth, check if auto mode needed */
        ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
        if (ret)
@@ -1184,45 +1184,49 @@ static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
        u8 tmp;
        *status = 0;
 
-       /* TPS lock */
-       ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
-       if (ret)
-               goto error;
-       if (tmp)
-               *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
        /* MPEG2 lock */
        ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
        if (ret)
                goto error;
        if (tmp)
-               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+                       FE_HAS_SYNC | FE_HAS_LOCK;
 
-       if (!(*status & FE_HAS_SIGNAL)) {
-               /* AGC lock */
-               ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+       if (!*status) {
+               /* TPS lock */
+               ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
                if (ret)
                        goto error;
                if (tmp)
-                       *status |= FE_HAS_SIGNAL;
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI;
        }
 
-       if (!(*status & FE_HAS_CARRIER)) {
+       if (!*status) {
                /* CFO lock */
                ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
                if (ret)
                        goto error;
                if (tmp)
-                       *status |= FE_HAS_CARRIER;
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
        }
 
-       if (!(*status & FE_HAS_CARRIER)) {
+       if (!*status) {
                /* SFOE lock */
                ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
                if (ret)
                        goto error;
                if (tmp)
-                       *status |= FE_HAS_CARRIER;
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+       }
+
+       if (!*status) {
+               /* AGC lock */
+               ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+               if (ret)
+                       goto error;
+               if (tmp)
+                       *status |= FE_HAS_SIGNAL;
        }
 
        ret = af9013_update_statistics(fe);
@@ -1574,7 +1578,7 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
 {
        int ret;
        struct af9013_state *state = NULL;
-       u8 buf[3], i;
+       u8 buf[4], i;
 
        /* allocate memory for the internal state */
        state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
@@ -1607,12 +1611,12 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
        }
 
        /* firmware version */
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i < 4; i++) {
                ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
                if (ret)
                        goto error;
        }
-       info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]);
+       info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
 
        /* settings for mp2if */
        if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
index e90fa92b1c1dc963033218f2558abaa2de84155c..72c71bb5d117a9a254e52c004b6220f8c90b03dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
  *
index 163e251d0b73d4f9410efdce047ab8f60c5d7e61..0fd42b7e248ea7f2bc347097b6f95ff6b314da23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
  *
@@ -132,6 +132,8 @@ static struct regdesc ofsm_init[] = {
        { 0xd740, 2, 1, 0x00 },
        { 0xd740, 3, 1, 0x01 },
        { 0xd3c1, 4, 1, 0x01 },
+       { 0x9124, 0, 8, 0x58 },
+       { 0x9125, 0, 2, 0x02 },
        { 0xd3a2, 0, 8, 0x00 },
        { 0xd3a3, 0, 8, 0x04 },
        { 0xd305, 0, 8, 0x32 },
@@ -143,7 +145,7 @@ static struct regdesc ofsm_init[] = {
        { 0x911b, 0, 1, 0x01 },
        { 0x9bce, 0, 4, 0x02 },
        { 0x9116, 0, 1, 0x01 },
-       { 0x9bd1, 0, 1, 0x01 },
+       { 0x9122, 0, 8, 0xd0 },
        { 0xd2e0, 0, 8, 0xd0 },
        { 0xd2e9, 0, 4, 0x0d },
        { 0xd38c, 0, 8, 0xfc },
@@ -165,7 +167,6 @@ static struct regdesc ofsm_init[] = {
        { 0xd081, 4, 4, 0x09 },
        { 0xd098, 4, 4, 0x0f },
        { 0xd098, 0, 4, 0x03 },
-       { 0xdbc0, 3, 1, 0x01 },
        { 0xdbc0, 4, 1, 0x01 },
        { 0xdbc7, 0, 8, 0x08 },
        { 0xdbc8, 4, 4, 0x00 },
@@ -179,6 +180,7 @@ static struct regdesc ofsm_init[] = {
        { 0xd0f0, 0, 7, 0x1a },
        { 0xd0f1, 4, 1, 0x01 },
        { 0xd0f2, 0, 8, 0x0c },
+       { 0xd101, 5, 3, 0x06 },
        { 0xd103, 0, 4, 0x08 },
        { 0xd0f8, 0, 7, 0x20 },
        { 0xd111, 5, 1, 0x00 },
index ad4c8cfd8090e7572c8204d9b8612c34d124c8c6..e80c5979636897f8517875fde1fd64f8a591d58f 100644 (file)
 #define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
 #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
-#endif
+
 #define deb_info(args...) dprintk(0x01,args)
 #define deb_i2c(args...)  dprintk(0x02,args)
 #define deb_srch(args...) dprintk(0x04,args)
@@ -51,12 +50,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
 #define deb_setf(args...) dprintk(0x04,args)
 #define deb_getf(args...) dprintk(0x08,args)
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
-#endif
-
 static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
 {
        u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
index 1a12747fdc914108bf6ee5f4d4bc26342b7c3392..16c526591f363c512e96d464b75548ee599a3dc3 100644 (file)
 
 /* debug */
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
 #define dprintk(level,args...) \
     do { if ((debug & level)) { printk(args); } } while (0)
-#else
-#define dprintk(args...) do { } while (0)
-#endif
 
 /* mask for enabling a specific pid for the pid_filter */
 #define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
index afad252abf4136dab0b83c60ef93ac35d66bfe92..088e7fadbe3db11d01828606ed478096086c5c51 100644 (file)
@@ -822,7 +822,7 @@ int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defa
 
        dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
        if (dmcst == NULL)
-               return -ENODEV;
+               return -ENOMEM;
 
        dmcst->i2c_adap = i2c;
 
index d69c775f8645419116f13befc0d4476cc2629016..3272881cb112922e30d829c010b9fde5fc3fe4f4 100644 (file)
@@ -1,7 +1,9 @@
 /*
- *    Support for LGDT3305 - VSB/QAM
+ *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
  *
- *    Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    LGDT3304 support by Jarod Wilson <jarod@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
@@ -65,6 +67,8 @@ struct lgdt3305_state {
 
 /* ------------------------------------------------------------------------ */
 
+/* FIXME: verify & document the LGDT3304 registers */
+
 #define LGDT3305_GEN_CTRL_1                   0x0000
 #define LGDT3305_GEN_CTRL_2                   0x0001
 #define LGDT3305_GEN_CTRL_3                   0x0002
@@ -358,7 +362,12 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
        case QAM_256:
                agcdelay = 0x046b;
                rfbw     = 0x8889;
-               ifbw     = 0x8888;
+               /* FIXME: investigate optimal ifbw & rfbw values for the
+                *        DT3304 and re-write this switch..case block */
+               if (state->cfg->demod_chip == LGDT3304)
+                       ifbw = 0x6666;
+               else /* (state->cfg->demod_chip == LGDT3305) */
+                       ifbw = 0x8888;
                break;
        default:
                return -EINVAL;
@@ -410,8 +419,18 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
        lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
 
        /* control agc function */
-       lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
-       lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+       switch (state->cfg->demod_chip) {
+       case LGDT3304:
+               lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
+               lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
+               break;
+       case LGDT3305:
+               lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
+               lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+               break;
+       default:
+               return -EINVAL;
+       }
 
        return lgdt3305_rfagc_loop(state, param);
 }
@@ -577,61 +596,79 @@ static int lgdt3305_init(struct dvb_frontend *fe)
        struct lgdt3305_state *state = fe->demodulator_priv;
        int ret;
 
+       static struct lgdt3305_reg lgdt3304_init_data[] = {
+               { .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
+               { .reg = 0x000d,                        .val = 0x02, },
+               { .reg = 0x000e,                        .val = 0x02, },
+               { .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
+               { .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
+               { .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTRL_7,            .val = 0xf9, },
+               { .reg = 0x0112,                        .val = 0x17, },
+               { .reg = 0x0113,                        .val = 0x15, },
+               { .reg = 0x0114,                        .val = 0x18, },
+               { .reg = 0x0115,                        .val = 0xff, },
+               { .reg = 0x0116,                        .val = 0x3c, },
+               { .reg = 0x0214,                        .val = 0x67, },
+               { .reg = 0x0424,                        .val = 0x8d, },
+               { .reg = 0x0427,                        .val = 0x12, },
+               { .reg = 0x0428,                        .val = 0x4f, },
+               { .reg = LGDT3305_IFBW_1,               .val = 0x80, },
+               { .reg = LGDT3305_IFBW_2,               .val = 0x00, },
+               { .reg = 0x030a,                        .val = 0x08, },
+               { .reg = 0x030b,                        .val = 0x9b, },
+               { .reg = 0x030d,                        .val = 0x00, },
+               { .reg = 0x030e,                        .val = 0x1c, },
+               { .reg = 0x0314,                        .val = 0xe1, },
+               { .reg = 0x000d,                        .val = 0x82, },
+               { .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
+               { .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
+       };
+
        static struct lgdt3305_reg lgdt3305_init_data[] = {
-               { .reg = LGDT3305_GEN_CTRL_1,
-                 .val = 0x03, },
-               { .reg = LGDT3305_GEN_CTRL_2,
-                 .val = 0xb0, },
-               { .reg = LGDT3305_GEN_CTRL_3,
-                 .val = 0x01, },
-               { .reg = LGDT3305_GEN_CONTROL,
-                 .val = 0x6f, },
-               { .reg = LGDT3305_GEN_CTRL_4,
-                 .val = 0x03, },
-               { .reg = LGDT3305_DGTL_AGC_REF_1,
-                 .val = 0x32, },
-               { .reg = LGDT3305_DGTL_AGC_REF_2,
-                 .val = 0xc4, },
-               { .reg = LGDT3305_CR_CTR_FREQ_1,
-                 .val = 0x00, },
-               { .reg = LGDT3305_CR_CTR_FREQ_2,
-                 .val = 0x00, },
-               { .reg = LGDT3305_CR_CTR_FREQ_3,
-                 .val = 0x00, },
-               { .reg = LGDT3305_CR_CTR_FREQ_4,
-                 .val = 0x00, },
-               { .reg = LGDT3305_CR_CTRL_7,
-                 .val = 0x79, },
-               { .reg = LGDT3305_AGC_POWER_REF_1,
-                 .val = 0x32, },
-               { .reg = LGDT3305_AGC_POWER_REF_2,
-                 .val = 0xc4, },
-               { .reg = LGDT3305_AGC_DELAY_PT_1,
-                 .val = 0x0d, },
-               { .reg = LGDT3305_AGC_DELAY_PT_2,
-                 .val = 0x30, },
-               { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1,
-                 .val = 0x80, },
-               { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2,
-                 .val = 0x00, },
-               { .reg = LGDT3305_IFBW_1,
-                 .val = 0x80, },
-               { .reg = LGDT3305_IFBW_2,
-                 .val = 0x00, },
-               { .reg = LGDT3305_AGC_CTRL_1,
-                 .val = 0x30, },
-               { .reg = LGDT3305_AGC_CTRL_4,
-                 .val = 0x61, },
-               { .reg = LGDT3305_FEC_BLOCK_CTRL,
-                 .val = 0xff, },
-               { .reg = LGDT3305_TP_CTRL_1,
-                 .val = 0x1b, },
+               { .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
+               { .reg = LGDT3305_GEN_CTRL_2,           .val = 0xb0, },
+               { .reg = LGDT3305_GEN_CTRL_3,           .val = 0x01, },
+               { .reg = LGDT3305_GEN_CONTROL,          .val = 0x6f, },
+               { .reg = LGDT3305_GEN_CTRL_4,           .val = 0x03, },
+               { .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
+               { .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
+               { .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
+               { .reg = LGDT3305_CR_CTRL_7,            .val = 0x79, },
+               { .reg = LGDT3305_AGC_POWER_REF_1,      .val = 0x32, },
+               { .reg = LGDT3305_AGC_POWER_REF_2,      .val = 0xc4, },
+               { .reg = LGDT3305_AGC_DELAY_PT_1,       .val = 0x0d, },
+               { .reg = LGDT3305_AGC_DELAY_PT_2,       .val = 0x30, },
+               { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
+               { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
+               { .reg = LGDT3305_IFBW_1,               .val = 0x80, },
+               { .reg = LGDT3305_IFBW_2,               .val = 0x00, },
+               { .reg = LGDT3305_AGC_CTRL_1,           .val = 0x30, },
+               { .reg = LGDT3305_AGC_CTRL_4,           .val = 0x61, },
+               { .reg = LGDT3305_FEC_BLOCK_CTRL,       .val = 0xff, },
+               { .reg = LGDT3305_TP_CTRL_1,            .val = 0x1b, },
        };
 
        lg_dbg("\n");
 
-       ret = lgdt3305_write_regs(state, lgdt3305_init_data,
-                                 ARRAY_SIZE(lgdt3305_init_data));
+       switch (state->cfg->demod_chip) {
+       case LGDT3304:
+               ret = lgdt3305_write_regs(state, lgdt3304_init_data,
+                                         ARRAY_SIZE(lgdt3304_init_data));
+               break;
+       case LGDT3305:
+               ret = lgdt3305_write_regs(state, lgdt3305_init_data,
+                                         ARRAY_SIZE(lgdt3305_init_data));
+               break;
+       default:
+               ret = -EINVAL;
+       }
        if (lg_fail(ret))
                goto fail;
 
@@ -640,6 +677,76 @@ fail:
        return ret;
 }
 
+static int lgdt3304_set_parameters(struct dvb_frontend *fe,
+                                  struct dvb_frontend_parameters *param)
+{
+       struct lgdt3305_state *state = fe->demodulator_priv;
+       int ret;
+
+       lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+
+       if (fe->ops.tuner_ops.set_params) {
+               ret = fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+               if (lg_fail(ret))
+                       goto fail;
+               state->current_frequency = param->frequency;
+       }
+
+       ret = lgdt3305_set_modulation(state, param);
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_passband_digital_agc(state, param);
+       if (lg_fail(ret))
+               goto fail;
+
+       ret = lgdt3305_agc_setup(state, param);
+       if (lg_fail(ret))
+               goto fail;
+
+       /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
+       switch (param->u.vsb.modulation) {
+       case VSB_8:
+               lgdt3305_write_reg(state, 0x030d, 0x00);
+               lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
+               lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
+               lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
+               lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
+               break;
+       case QAM_64:
+       case QAM_256:
+               lgdt3305_write_reg(state, 0x030d, 0x14);
+               ret = lgdt3305_set_if(state, param);
+               if (lg_fail(ret))
+                       goto fail;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       ret = lgdt3305_spectral_inversion(state, param,
+                                         state->cfg->spectral_inversion
+                                         ? 1 : 0);
+       if (lg_fail(ret))
+               goto fail;
+
+       state->current_modulation = param->u.vsb.modulation;
+
+       ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+       if (lg_fail(ret))
+               goto fail;
+
+       /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+       ret = lgdt3305_mpeg_mode_polarity(state,
+                                         state->cfg->tpclk_edge,
+                                         state->cfg->tpvalid_polarity);
+fail:
+       return ret;
+}
+
 static int lgdt3305_set_parameters(struct dvb_frontend *fe,
                                   struct dvb_frontend_parameters *param)
 {
@@ -848,6 +955,10 @@ static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
        switch (state->current_modulation) {
        case QAM_256:
        case QAM_64:
+               /* signal bit is unreliable on the DT3304 in QAM mode */
+               if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
+                       *status |= FE_HAS_SIGNAL;
+
                ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
                if (lg_fail(ret))
                        goto fail;
@@ -993,6 +1104,7 @@ static void lgdt3305_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
+static struct dvb_frontend_ops lgdt3304_ops;
 static struct dvb_frontend_ops lgdt3305_ops;
 
 struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
@@ -1013,11 +1125,21 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
        state->cfg = config;
        state->i2c_adap = i2c_adap;
 
-       memcpy(&state->frontend.ops, &lgdt3305_ops,
-              sizeof(struct dvb_frontend_ops));
+       switch (config->demod_chip) {
+       case LGDT3304:
+               memcpy(&state->frontend.ops, &lgdt3304_ops,
+                      sizeof(struct dvb_frontend_ops));
+               break;
+       case LGDT3305:
+               memcpy(&state->frontend.ops, &lgdt3305_ops,
+                      sizeof(struct dvb_frontend_ops));
+               break;
+       default:
+               goto fail;
+       }
        state->frontend.demodulator_priv = state;
 
-       /* verify that we're talking to a lg dt3305 */
+       /* verify that we're talking to a lg dt3304/5 */
        ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
        if ((lg_fail(ret)) | (val == 0))
                goto fail;
@@ -1036,12 +1158,35 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
 
        return &state->frontend;
 fail:
-       lg_warn("unable to detect LGDT3305 hardware\n");
+       lg_warn("unable to detect %s hardware\n",
+               config->demod_chip ? "LGDT3304" : "LGDT3305");
        kfree(state);
        return NULL;
 }
 EXPORT_SYMBOL(lgdt3305_attach);
 
+static struct dvb_frontend_ops lgdt3304_ops = {
+       .info = {
+               .name = "LG Electronics LGDT3304 VSB/QAM Frontend",
+               .type               = FE_ATSC,
+               .frequency_min      = 54000000,
+               .frequency_max      = 858000000,
+               .frequency_stepsize = 62500,
+               .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+       },
+       .i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
+       .init                 = lgdt3305_init,
+       .set_frontend         = lgdt3304_set_parameters,
+       .get_frontend         = lgdt3305_get_frontend,
+       .get_tune_settings    = lgdt3305_get_tune_settings,
+       .read_status          = lgdt3305_read_status,
+       .read_ber             = lgdt3305_read_ber,
+       .read_signal_strength = lgdt3305_read_signal_strength,
+       .read_snr             = lgdt3305_read_snr,
+       .read_ucblocks        = lgdt3305_read_ucblocks,
+       .release              = lgdt3305_release,
+};
+
 static struct dvb_frontend_ops lgdt3305_ops = {
        .info = {
                .name = "LG Electronics LGDT3305 VSB/QAM Frontend",
@@ -1065,10 +1210,10 @@ static struct dvb_frontend_ops lgdt3305_ops = {
        .release              = lgdt3305_release,
 };
 
-MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
 
 /*
  * Local variables:
index 9cb11c9cae53eb4ad097165b9065e589bc5a3325..02172eca4d47e74c2e22d364fb5409e593944888 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *    Support for LGDT3305 - VSB/QAM
+ *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
  *
- *    Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.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
@@ -41,6 +41,11 @@ enum lgdt3305_tp_valid_polarity {
        LGDT3305_TP_VALID_HIGH = 1,
 };
 
+enum lgdt_demod_chip_type {
+       LGDT3305 = 0,
+       LGDT3304 = 1,
+};
+
 struct lgdt3305_config {
        u8 i2c_addr;
 
@@ -65,6 +70,7 @@ struct lgdt3305_config {
        enum lgdt3305_mpeg_mode mpeg_mode;
        enum lgdt3305_tp_clock_edge tpclk_edge;
        enum lgdt3305_tp_valid_polarity tpvalid_polarity;
+       enum lgdt_demod_chip_type demod_chip;
 };
 
 #if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
index dee53960e7e8f79966763c0f64107db55313f5ba..5ea28ae2ba8f87a09ee03c29bfe52f0d3df977d7 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <asm/div64.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
 
@@ -46,42 +47,6 @@ module_param(fake_signal_str, int, 0644);
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
 "Signal strength calculation is slow.(default:on).");
 
-static const u8 lgs8g75_initdat[] = {
-       0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
-       0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
-       0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
-       0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
-       0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
-       0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
-       0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
-       0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
-       0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
-       0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
-       0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
-       0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
-       0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
-       0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
-       0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
-       0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
-       0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
-       0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
-       0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
-       0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
-       0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
-       0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
-       0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
-       0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
-       0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
-       0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
-};
-
 /* LGS8GXX internal helper functions */
 
 static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -627,9 +592,14 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
 
 static int lgs8g75_init_data(struct lgs8gxx_state *priv)
 {
-       const u8 *p = lgs8g75_initdat;
+       const struct firmware *fw;
+       int rc;
        int i;
 
+       rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev);
+       if (rc)
+               return rc;
+
        lgs8gxx_write_reg(priv, 0xC6, 0x40);
 
        lgs8gxx_write_reg(priv, 0x3D, 0x04);
@@ -640,16 +610,16 @@ static int lgs8g75_init_data(struct lgs8gxx_state *priv)
        lgs8gxx_write_reg(priv, 0x3B, 0x00);
        lgs8gxx_write_reg(priv, 0x38, 0x00);
 
-       for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
+       for (i = 0; i < fw->size; i++) {
                lgs8gxx_write_reg(priv, 0x38, 0x00);
                lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
                lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
-               lgs8gxx_write_reg(priv, 0x3C, *p);
-               p++;
+               lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
        }
 
        lgs8gxx_write_reg(priv, 0x38, 0x00);
 
+       release_firmware(fw);
        return 0;
 }
 
index 599d1aa519a31ca160306471c237a1ba362a7ba3..33b63235b86e993f32e8489a87d2be7879d41641 100644 (file)
@@ -1833,7 +1833,6 @@ static struct dvb_frontend_ops mb86a16_ops = {
 
        .get_frontend_algo              = mb86a16_frontend_algo,
        .search                         = mb86a16_search,
-       .read_status                    = mb86a16_read_status,
        .init                           = mb86a16_init,
        .sleep                          = mb86a16_sleep,
        .read_status                    = mb86a16_read_status,
index 4e2a7c8b2f624e41f4d33adb27ef717f5172ae79..93f6a75c238eec25fbe2c8cfb905f08d113d5e2a 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/math64.h>
 #include <asm/div64.h>
 #include "dvb_frontend.h"
 #include "dvb_math.h"
@@ -49,8 +50,8 @@
 #define TDA10048_CONF_C4_1         0x1E
 #define TDA10048_CONF_C4_2         0x1F
 #define TDA10048_CODE_IN_RAM       0x20
-#define TDA10048_CHANNEL_INFO_1_R  0x22
-#define TDA10048_CHANNEL_INFO_2_R  0x23
+#define TDA10048_CHANNEL_INFO1_R   0x22
+#define TDA10048_CHANNEL_INFO2_R   0x23
 #define TDA10048_CHANNEL_INFO1     0x24
 #define TDA10048_CHANNEL_INFO2     0x25
 #define TDA10048_TIME_ERROR_R      0x26
@@ -63,8 +64,8 @@
 #define TDA10048_IT_STAT           0x32
 #define TDA10048_DSP_AD_LSB        0x3C
 #define TDA10048_DSP_AD_MSB        0x3D
-#define TDA10048_DSP_REF_LSB       0x3E
-#define TDA10048_DSP_REF_MSB       0x3F
+#define TDA10048_DSP_REG_LSB       0x3E
+#define TDA10048_DSP_REG_MSB       0x3F
 #define TDA10048_CONF_TRISTATE1    0x44
 #define TDA10048_CONF_TRISTATE2    0x45
 #define TDA10048_CONF_POLARITY     0x46
 #define TDA10048_FREE_REG_1        0xB2
 #define TDA10048_FREE_REG_2        0xB3
 #define TDA10048_CONF_C3_1         0xC0
-#define TDA10048_CYBER_CTRL        0xC2
+#define TDA10048_CVBER_CTRL        0xC2
 #define TDA10048_CBER_NMAX_LSB     0xC4
 #define TDA10048_CBER_NMAX_MSB     0xC5
 #define TDA10048_CBER_LSB          0xC6
 #define TDA10048_VBER_LSB          0xC8
 #define TDA10048_VBER_MID          0xC9
 #define TDA10048_VBER_MSB          0xCA
-#define TDA10048_CYBER_LUT         0xCC
+#define TDA10048_CVBER_LUT         0xCC
 #define TDA10048_UNCOR_CTRL        0xCD
 #define TDA10048_UNCOR_CPT_LSB     0xCE
 #define TDA10048_UNCOR_CPT_MSB     0xCF
@@ -183,7 +184,7 @@ static struct init_tab {
        { TDA10048_AGC_IF_MAX, 0xff },
        { TDA10048_AGC_THRESHOLD_MSB, 0x00 },
        { TDA10048_AGC_THRESHOLD_LSB, 0x70 },
-       { TDA10048_CYBER_CTRL, 0x38 },
+       { TDA10048_CVBER_CTRL, 0x38 },
        { TDA10048_AGC_GAINS, 0x12 },
        { TDA10048_CONF_XO, 0x00 },
        { TDA10048_CONF_TS1, 0x07 },
@@ -688,7 +689,7 @@ static int tda10048_get_tps(struct tda10048_state *state,
                p->guard_interval =  GUARD_INTERVAL_1_4;
                break;
        }
-       switch (val & 0x02) {
+       switch (val & 0x03) {
        case 0:
                p->transmission_mode = TRANSMISSION_MODE_2K;
                break;
@@ -765,6 +766,8 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 
        /* Enable demod TPS auto detection and begin acquisition */
        tda10048_writereg(state, TDA10048_AUTO, 0x57);
+       /* trigger cber and vber acquisition */
+       tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
 
        return 0;
 }
@@ -830,12 +833,27 @@ static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
 static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       static u32 cber_current;
+       u32 cber_nmax;
+       u64 cber_tmp;
 
        dprintk(1, "%s()\n", __func__);
 
-       /* TODO: A reset may be required here */
-       *ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
-               tda10048_readreg(state, TDA10048_CBER_LSB);
+       /* update cber on interrupt */
+       if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
+               cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+                       tda10048_readreg(state, TDA10048_CBER_LSB);
+               cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
+                       tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
+               cber_tmp *= 100000000;
+               cber_tmp *= 2;
+               cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
+               cber_current = (u32)cber_tmp;
+               /* retrigger cber acquisition */
+               tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
+       }
+       /* actual cber is (*ber)/1e8 */
+       *ber = cber_current;
 
        return 0;
 }
@@ -1015,6 +1033,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 
        *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
                tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+       /* clear the uncorrected TS packets counter when saturated */
+       if (*ucblocks == 0xFFFF)
+               tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
 
        return 0;
 }
index f7b72a32adf38b36720d67ba8d5963cacae5995c..decdeda840d01158f070a2dcf8778c1c749d41a8 100644 (file)
@@ -10,9 +10,15 @@ config MANTIS_CORE
 config DVB_MANTIS
        tristate "MANTIS based cards"
        depends on MANTIS_CORE && DVB_CORE && PCI && I2C
-       select DVB_MB86A16
-       select DVB_ZL10353
-       select DVB_STV0299
+       select DVB_MB86A16 if !DVB_FE_CUSTOMISE
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_STB0899 if !DVB_FE_CUSTOMISE
+       select DVB_STB6100 if !DVB_FE_CUSTOMISE
+       select DVB_TDA665x if !DVB_FE_CUSTOMISE
+       select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+       select DVB_TDA10023 if !DVB_FE_CUSTOMISE
        select DVB_PLL
        help
          Support for PCI cards based on the Mantis PCI bridge.
@@ -23,7 +29,7 @@ config DVB_MANTIS
 config DVB_HOPPER
        tristate "HOPPER based cards"
        depends on MANTIS_CORE && DVB_CORE && PCI && I2C
-       select DVB_ZL10353
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_PLL
        help
          Support for PCI cards based on the Hopper  PCI bridge.
index 3d4e4663220c21ac08ed31c98542851529be4f8f..a99489b8418b4e49890e1411020367571a63a325 100644 (file)
@@ -19,7 +19,7 @@
 */
 
 #include <linux/input.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 #include <linux/pci.h>
 
 #include "dmxdev.h"
@@ -104,7 +104,6 @@ EXPORT_SYMBOL_GPL(ir_mantis);
 int mantis_input_init(struct mantis_pci *mantis)
 {
        struct input_dev *rc;
-       struct ir_input_state rc_state;
        char name[80], dev[80];
        int err;
 
@@ -120,8 +119,6 @@ int mantis_input_init(struct mantis_pci *mantis)
        rc->name = name;
        rc->phys = dev;
 
-       ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
-
        rc->id.bustype  = BUS_PCI;
        rc->id.vendor   = mantis->vendor_id;
        rc->id.product  = mantis->device_id;
index cff77e2eb55704ad3a7e7ca53c8c0dbbd186a91f..25b43e587fa6c274142debf1a0ec3ab2f5593c7f 100644 (file)
@@ -64,9 +64,11 @@ 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,
                .board_cfg.leds_power = 26,
                .board_cfg.led0 = 27,
                .board_cfg.led1 = 28,
+               .board_cfg.ir = 9,
                .led_power = 26,
                .led_lo    = 27,
                .led_hi    = 28,
index 8f19fc000b46914d8afb98810e06f1c1890d2711..d8cdf756f7cf072073cf018638746af19c7baf04 100644 (file)
@@ -75,7 +75,7 @@ struct sms_board {
        enum sms_device_type_st type;
        char *name, *fw[DEVICE_MODE_MAX];
        struct sms_board_gpio_cfg board_cfg;
-       enum ir_kb_type ir_kb_type;
+       char *rc_codes;                         /* Name of IR codes table */
 
        /* gpios */
        int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
index 0c87a3c3899ada10eceee75b0cd2ec07be1030fc..828bcc2e129be683bf6c9d872d3d65424c1a33d9 100644 (file)
@@ -116,9 +116,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
                        return entry;
                }
        }
-       entry = (struct smscore_registry_entry_t *)
-                       kmalloc(sizeof(struct smscore_registry_entry_t),
-                               GFP_KERNEL);
+       entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
        if (entry) {
                entry->mode = default_mode;
                strcpy(entry->devpath, devpath);
index a56eac76e0f0c95738d4faa3a00896b584296795..d0e4639ee9db3c8d7768b4199b1526ec6d40986c 100644 (file)
@@ -4,6 +4,11 @@
  MDTV receiver kernel modules.
  Copyright (C) 2006-2009, Uri Shkolnik
 
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+       - Ported the driver to use rc-core
+       - IR raw event decoding is now done at rc-core
+       - Code almost re-written
+
  This program is free software: 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
 #include "smsir.h"
 #include "sms-cards.h"
 
-/* In order to add new IR remote control -
- * 1) Add it to the <enum ir_kb_type> @ smsir,h,
- * 2) Add its map to keyboard_layout_maps below
- * 3) Set your board (sms-cards sub-module) to use it
- */
-
-static struct keyboard_layout_map_t keyboard_layout_maps[] = {
-               [SMS_IR_KB_DEFAULT_TV] = {
-                       .ir_protocol = IR_RC5,
-                       .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
-                       .keyboard_layout_map = {
-                                       KEY_0, KEY_1, KEY_2,
-                                       KEY_3, KEY_4, KEY_5,
-                                       KEY_6, KEY_7, KEY_8,
-                                       KEY_9, 0, 0, KEY_POWER,
-                                       KEY_MUTE, 0, 0,
-                                       KEY_VOLUMEUP, KEY_VOLUMEDOWN,
-                                       KEY_BRIGHTNESSUP,
-                                       KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
-                                       KEY_CHANNELDOWN,
-                                       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
-                       }
-               },
-               [SMS_IR_KB_HCW_SILVER] = {
-                       .ir_protocol = IR_RC5,
-                       .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
-                       .keyboard_layout_map = {
-                                       KEY_0, KEY_1, KEY_2,
-                                       KEY_3, KEY_4, KEY_5,
-                                       KEY_6, KEY_7, KEY_8,
-                                       KEY_9, KEY_TEXT, KEY_RED,
-                                       KEY_RADIO, KEY_MENU,
-                                       KEY_SUBTITLE,
-                                       KEY_MUTE, KEY_VOLUMEUP,
-                                       KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
-                                       KEY_UP, KEY_DOWN, KEY_LEFT,
-                                       KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
-                                       KEY_MHP, KEY_EPG, KEY_TV,
-                                       0, KEY_NEXTSONG, KEY_EXIT,
-                                       KEY_CHANNELUP,  KEY_CHANNELDOWN,
-                                       KEY_CHANNEL, 0,
-                                       KEY_PREVIOUSSONG, KEY_ENTER,
-                                       KEY_SLEEP, 0, 0, KEY_BLUE,
-                                       0, 0, 0, 0, KEY_GREEN, 0,
-                                       KEY_PAUSE, 0, KEY_REWIND,
-                                       0, KEY_FASTFORWARD, KEY_PLAY,
-                                       KEY_STOP, KEY_RECORD,
-                                       KEY_YELLOW, 0, 0, KEY_SELECT,
-                                       KEY_ZOOM, KEY_POWER, 0, 0
-                       }
-               },
-               { } /* Terminating entry */
-};
-
-static u32 ir_pos;
-static u32 ir_word;
-static u32 ir_toggle;
-
-#define RC5_PUSH_BIT(dst, bit, pos)    \
-       { dst <<= 1; dst |= bit; pos++; }
-
-
-static void sms_ir_rc5_event(struct smscore_device_t *coredev,
-                               u32 toggle, u32 addr, u32 cmd)
-{
-       bool toggle_changed;
-       u16 keycode;
-
-       sms_log("IR RC5 word: address %d, command %d, toggle %d",
-                               addr, cmd, toggle);
-
-       toggle_changed = ir_toggle != toggle;
-       /* keep toggle */
-       ir_toggle = toggle;
-
-       if (addr !=
-               keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
-               return; /* Check for valid address */
-
-       keycode =
-               keyboard_layout_maps
-               [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
+#define MODULE_NAME "smsmdtv"
 
-       if (!toggle_changed &&
-                       (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
-               return; /* accept only repeated volume, reject other keys */
-
-       sms_log("kernel input keycode (from ir) %d", keycode);
-       input_report_key(coredev->ir.input_dev, keycode, 1);
-       input_sync(coredev->ir.input_dev);
-
-}
-
-/* decode raw bit pattern to RC5 code */
-/* taken from ir-functions.c */
-static u32 ir_rc5_decode(unsigned int code)
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
 {
-/*     unsigned int org_code = code;*/
-       unsigned int pair;
-       unsigned int rc5 = 0;
        int i;
+       const s32 *samples = (const void *)buf;
 
-       for (i = 0; i < 14; ++i) {
-               pair = code & 0x3;
-               code >>= 2;
-
-               rc5 <<= 1;
-               switch (pair) {
-               case 0:
-               case 2:
-                       break;
-               case 1:
-                       rc5 |= 1;
-                       break;
-               case 3:
-/*     dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
-                       sms_log("bad code");
-                       return 0;
-               }
-       }
-/*
-       dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
-               toggle=%x, address=%x, "
-               "instr=%x\n", rc5, org_code, RC5_START(rc5),
-               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
-*/
-       return rc5;
-}
-
-static void sms_rc5_parse_word(struct smscore_device_t *coredev)
-{
-       #define RC5_START(x)    (((x)>>12)&3)
-       #define RC5_TOGGLE(x)   (((x)>>11)&1)
-       #define RC5_ADDR(x)     (((x)>>6)&0x1F)
-       #define RC5_INSTR(x)    ((x)&0x3F)
-
-       int i, j;
-       u32 rc5_word = 0;
-
-       /* Reverse the IR word direction */
-       for (i = 0 ; i < 28 ; i++)
-               RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
-
-       rc5_word = ir_rc5_decode(rc5_word);
-       /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
-
-       sms_ir_rc5_event(coredev,
-                               RC5_TOGGLE(rc5_word),
-                               RC5_ADDR(rc5_word),
-                               RC5_INSTR(rc5_word));
-}
-
-
-static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
-               s32 ir_sample)
-{
-       #define RC5_TIME_GRANULARITY    200
-       #define RC5_DEF_BIT_TIME                889
-       #define RC5_MAX_SAME_BIT_CONT   4
-       #define RC5_WORD_LEN                    27 /* 28 bit */
-
-       u32 i, j;
-       s32 delta_time;
-       u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
-       u32 level = (ir_sample < 0) ? 0 : 1;
-
-       for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
-               delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
-               if (delta_time < 0)
-                       continue; /* not so many consecutive bits */
-               if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
-                       /* timeout */
-                       if (ir_pos == (RC5_WORD_LEN-1))
-                               /* complete last bit */
-                               RC5_PUSH_BIT(ir_word, level, ir_pos)
-
-                       if (ir_pos == RC5_WORD_LEN)
-                               sms_rc5_parse_word(coredev);
-                       else if (ir_pos) /* timeout within a word */
-                               sms_log("IR error parsing a word");
+       for (i = 0; i < len >> 2; i++) {
+               struct ir_raw_event ev;
 
-                       ir_pos = 0;
-                       ir_word = 0;
-                       /* sms_log("timeout %d", time); */
-                       break;
-               }
-               /* The time is within the range of this number of bits */
-               for (j = 0 ; j < i ; j++)
-                       RC5_PUSH_BIT(ir_word, level, ir_pos)
+               ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
+               ev.pulse = (samples[i] > 0) ? false : true;
 
-               break;
+               ir_raw_event_store(coredev->ir.input_dev, &ev);
        }
-}
-
-void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
-{
-       #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
-       u32 i;
-       enum ir_protocol ir_protocol =
-                       keyboard_layout_maps[coredev->ir.ir_kb_type]
-                                            .ir_protocol;
-       s32 *samples;
-       int count = len>>2;
-
-       samples = (s32 *)buf;
-/*     sms_log("IR buffer received, length = %d", count);*/
-
-       for (i = 0; i < count; i++)
-               if (ir_protocol == IR_RC5)
-                       sms_rc5_accumulate_bits(coredev, samples[i]);
-       /*  IR_RCMM not implemented */
+       ir_raw_event_handle(coredev->ir.input_dev);
 }
 
 int sms_ir_init(struct smscore_device_t *coredev)
 {
        struct input_dev *input_dev;
+       int board_id = smscore_get_board_id(coredev);
 
        sms_log("Allocating input device");
        input_dev = input_allocate_device();
@@ -256,33 +63,38 @@ int sms_ir_init(struct smscore_device_t *coredev)
        }
 
        coredev->ir.input_dev = input_dev;
-       coredev->ir.ir_kb_type =
-               sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
-       coredev->ir.keyboard_layout_map =
-               keyboard_layout_maps[coredev->ir.ir_kb_type].
-                               keyboard_layout_map;
-       sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
 
        coredev->ir.controller = 0;     /* Todo: vega/nova SPI number */
        coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
        sms_log("IR port %d, timeout %d ms",
                        coredev->ir.controller, coredev->ir.timeout);
 
-       snprintf(coredev->ir.name,
-                               IR_DEV_NAME_MAX_LEN,
-                               "SMS IR w/kbd type %d",
-                               coredev->ir.ir_kb_type);
+       snprintf(coredev->ir.name, sizeof(coredev->ir.name),
+                "SMS IR (%s)", sms_get_board(board_id)->name);
+
+       strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
+       strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
+
        input_dev->name = coredev->ir.name;
-       input_dev->phys = coredev->ir.name;
+       input_dev->phys = coredev->ir.phys;
        input_dev->dev.parent = coredev->device;
 
-       /* Key press events only */
-       input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+#if 0
+       /* TODO: properly initialize the parameters bellow */
+       input_dev->id.bustype = BUS_USB;
+       input_dev->id.version = 1;
+       input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+       input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+#endif
+
+       coredev->ir.props.priv = coredev;
+       coredev->ir.props.driver_type = RC_DRIVER_IR_RAW;
+       coredev->ir.props.allowed_protos = IR_TYPE_ALL;
 
        sms_log("Input device (IR) %s is set for key events", input_dev->name);
 
-       if (input_register_device(input_dev)) {
+       if (ir_input_register(input_dev, sms_get_board(board_id)->rc_codes,
+                             &coredev->ir.props, MODULE_NAME)) {
                sms_err("Failed to register device");
                input_free_device(input_dev);
                return -EACCES;
@@ -294,8 +106,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 void sms_ir_exit(struct smscore_device_t *coredev)
 {
        if (coredev->ir.input_dev)
-               input_unregister_device(coredev->ir.input_dev);
+               ir_input_unregister(coredev->ir.input_dev);
 
        sms_log("");
 }
-
index b7d703e2d338bf73830303969903063b02f297f2..926e247523bd149d3185c0a4b4d965dab41fd354 100644 (file)
@@ -4,6 +4,11 @@ Siano Mobile Silicon, Inc.
 MDTV receiver kernel modules.
 Copyright (C) 2006-2009, Uri Shkolnik
 
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+       - Ported the driver to use rc-core
+       - IR raw event decoding is now done at rc-core
+       - Code almost re-written
+
 This program is free software: 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
@@ -23,63 +28,21 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define __SMS_IR_H__
 
 #include <linux/input.h>
+#include <media/ir-core.h>
 
-#define IR_DEV_NAME_MAX_LEN            23 /* "SMS IR kbd type nn\0" */
-#define IR_KEYBOARD_LAYOUT_SIZE        64
 #define IR_DEFAULT_TIMEOUT             100
 
-enum ir_kb_type {
-       SMS_IR_KB_DEFAULT_TV,
-       SMS_IR_KB_HCW_SILVER
-};
-
-enum rc5_keyboard_address {
-       KEYBOARD_ADDRESS_TV1 = 0,
-       KEYBOARD_ADDRESS_TV2 = 1,
-       KEYBOARD_ADDRESS_TELETEXT = 2,
-       KEYBOARD_ADDRESS_VIDEO = 3,
-       KEYBOARD_ADDRESS_LV1 = 4,
-       KEYBOARD_ADDRESS_VCR1 = 5,
-       KEYBOARD_ADDRESS_VCR2 = 6,
-       KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
-       KEYBOARD_ADDRESS_SAT1 = 8,
-       KEYBOARD_ADDRESS_CAMERA = 9,
-       KEYBOARD_ADDRESS_SAT2 = 10,
-       KEYBOARD_ADDRESS_CDV = 12,
-       KEYBOARD_ADDRESS_CAMCORDER = 13,
-       KEYBOARD_ADDRESS_PRE_AMP = 16,
-       KEYBOARD_ADDRESS_TUNER = 17,
-       KEYBOARD_ADDRESS_RECORDER1 = 18,
-       KEYBOARD_ADDRESS_PRE_AMP1 = 19,
-       KEYBOARD_ADDRESS_CD_PLAYER = 20,
-       KEYBOARD_ADDRESS_PHONO = 21,
-       KEYBOARD_ADDRESS_SATA = 22,
-       KEYBOARD_ADDRESS_RECORDER2 = 23,
-       KEYBOARD_ADDRESS_CDR = 26,
-       KEYBOARD_ADDRESS_LIGHTING = 29,
-       KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
-       KEYBOARD_ADDRESS_PHONE = 31,
-       KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
-};
-
-enum ir_protocol {
-       IR_RC5,
-       IR_RCMM
-};
-
-struct keyboard_layout_map_t {
-       enum ir_protocol ir_protocol;
-       enum rc5_keyboard_address rc5_kbd_address;
-       u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
-};
-
 struct smscore_device_t;
 
 struct ir_t {
        struct input_dev *input_dev;
-       enum ir_kb_type ir_kb_type;
-       char name[IR_DEV_NAME_MAX_LEN+1];
-       u16 *keyboard_layout_map;
+       char name[40];
+       char phys[32];
+
+       char *rc_codes;
+       u64 protocol;
+       struct ir_dev_props props;
+
        u32 timeout;
        u32 controller;
 };
index a9c27fb69ba747272393bb033c65d4f48a7e194d..50d4338610e023b3fb76b44867fa8a162bfd3ab7 100644 (file)
@@ -352,8 +352,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
        params.num_buffers = MAX_BUFFERS;
        params.sendrequest_handler = smsusb_sendrequest;
        params.context = dev;
-       snprintf(params.devpath, sizeof(params.devpath),
-                "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+       usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
 
        /* register in smscore */
        rc = smscore_register_device(&params, &dev->coredev);
index 47075fc71f112a8e7be6b6dfac8133a1ad9ab490..9927a595b426a285f2755d608631200a51a3a0e7 100644 (file)
@@ -748,7 +748,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
                struct v4l2_tuner *tuner)
 {
        struct si470x_device *radio = video_drvdata(file);
-       int retval = -EINVAL;
+       int retval = 0;
 
        /* safety checks */
        retval = si470x_disconnect_check(radio);
index ab63dd5b25c44798523f51a6b4d88199b9e95c7a..fc7f4b7946498be041778d70486d0a2b721ac7d2 100644 (file)
@@ -1009,8 +1009,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
                        goto exit;
                }
                rval = copy_from_user(ps_name, control->string, len);
-               if (rval < 0)
+               if (rval) {
+                       rval = -EFAULT;
                        goto exit;
+               }
                ps_name[len] = '\0';
 
                if (strlen(ps_name) % vqc.step) {
@@ -1031,8 +1033,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
                        goto exit;
                }
                rval = copy_from_user(radio_text, control->string, len);
-               if (rval < 0)
+               if (rval) {
+                       rval = -EFAULT;
                        goto exit;
+               }
                radio_text[len] = '\0';
 
                if (strlen(radio_text) % vqc.step) {
@@ -1367,6 +1371,8 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev,
                }
                rval = copy_to_user(control->string, sdev->rds_info.ps_name,
                                        strlen(sdev->rds_info.ps_name) + 1);
+               if (rval)
+                       rval = -EFAULT;
                break;
 
        case V4L2_CID_RDS_TX_RADIO_TEXT:
@@ -1377,6 +1383,8 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev,
                }
                rval = copy_to_user(control->string, sdev->rds_info.radio_text,
                                        strlen(sdev->rds_info.radio_text) + 1);
+               if (rval)
+                       rval = -EFAULT;
                break;
 
        default:
index bdbc9d305419d8778d7bfceded703e1fb55d4c9b..2e15903b976d79064b53a22e3cbc4210a7fb55cf 100644 (file)
@@ -517,19 +517,6 @@ config VIDEO_UPD64083
 
 endmenu # encoder / decoder chips
 
-config DISPLAY_DAVINCI_DM646X_EVM
-       tristate "DM646x EVM Video Display"
-       depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
-       select VIDEOBUF_DMA_CONTIG
-       select VIDEO_DAVINCI_VPIF
-       select VIDEO_ADV7343
-       select VIDEO_THS7303
-       help
-         Support for DM6467 based display device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vpif_display.
-
 config VIDEO_SH_VOU
        tristate "SuperH VOU video output driver"
        depends on VIDEO_DEV && ARCH_SHMOBILE
@@ -537,29 +524,22 @@ config VIDEO_SH_VOU
        help
          Support for the Video Output Unit (VOU) on SuperH SoCs.
 
-config CAPTURE_DAVINCI_DM646X_EVM
-       tristate "DM646x EVM Video Capture"
-       depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+config VIDEO_VIU
+       tristate "Freescale VIU Video Driver"
+       depends on VIDEO_V4L2 && PPC_MPC512x
        select VIDEOBUF_DMA_CONTIG
-       select VIDEO_DAVINCI_VPIF
-       help
-         Support for DM6467 based capture device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vpif_capture.
-
-config VIDEO_DAVINCI_VPIF
-       tristate "DaVinci VPIF Driver"
-       depends on DISPLAY_DAVINCI_DM646X_EVM
-       help
-         Support for DaVinci VPIF Driver.
+       default y
+       ---help---
+         Support for Freescale VIU video driver. This device captures
+         video data, or overlays video on DIU frame buffer.
 
-         To compile this driver as a module, choose M here: the
-         module will be called vpif.
+         Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+         In doubt, say N.
 
 config VIDEO_VIVI
        tristate "Virtual Video Driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FONTS
+       depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+       depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS
        select FONT_8x16
        select VIDEOBUF_VMALLOC
        default n
@@ -570,66 +550,7 @@ config VIDEO_VIVI
          Say Y here if you want to test video apps or debug V4L devices.
          In doubt, say N.
 
-config VIDEO_VPSS_SYSTEM
-       tristate "VPSS System module driver"
-       depends on ARCH_DAVINCI
-       help
-         Support for vpss system module for video driver
-
-config VIDEO_VPFE_CAPTURE
-       tristate "VPFE Video Capture Driver"
-       depends on VIDEO_V4L2 && ARCH_DAVINCI
-       select VIDEOBUF_DMA_CONTIG
-       help
-         Support for DMXXXX VPFE based frame grabber. This is the
-         common V4L2 module for following DMXXX SoCs from Texas
-         Instruments:- DM6446 & DM355.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vpfe-capture.
-
-config VIDEO_DM6446_CCDC
-       tristate "DM6446 CCDC HW module"
-       depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
-       select VIDEO_VPSS_SYSTEM
-       default y
-       help
-          Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
-          with decoder modules such as TVP5146 over BT656 or
-          sensor module such as MT9T001 over a raw interface. This
-          module configures the interface and CCDC/ISIF to do
-          video frame capture from slave decoders.
-
-          To compile this driver as a module, choose M here: the
-          module will be called vpfe.
-
-config VIDEO_DM355_CCDC
-       tristate "DM355 CCDC HW module"
-       depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
-       select VIDEO_VPSS_SYSTEM
-       default y
-       help
-          Enables DM355 CCD hw module. DM355 CCDC hw interfaces
-          with decoder modules such as TVP5146 over BT656 or
-          sensor module such as MT9T001 over a raw interface. This
-          module configures the interface and CCDC/ISIF to do
-          video frame capture from a slave decoders
-
-          To compile this driver as a module, choose M here: the
-          module will be called vpfe.
-
-config VIDEO_ISIF
-       tristate "ISIF HW module"
-       depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
-       select VIDEO_VPSS_SYSTEM
-       default y
-       help
-          Enables ISIF hw module. This is the hardware module for
-          configuring ISIF in VPFE to capture Raw Bayer RGB data  from
-          a image sensor or YUV data from a YUV source.
-
-          To compile this driver as a module, choose M here: the
-          module will be called vpfe.
+source "drivers/media/video/davinci/Kconfig"
 
 source "drivers/media/video/omap/Kconfig"
 
@@ -955,6 +876,12 @@ config VIDEO_PXA27x
        ---help---
          This is a v4l2 driver for the PXA27x Quick Capture Interface
 
+config VIDEO_SH_MOBILE_CSI2
+       tristate "SuperH Mobile MIPI CSI-2 Interface driver"
+       depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+       ---help---
+         This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
+
 config VIDEO_SH_MOBILE_CEU
        tristate "SuperH Mobile CEU Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
@@ -969,6 +896,19 @@ config VIDEO_OMAP2
        ---help---
          This is a v4l2 driver for the TI OMAP2 camera capture interface
 
+config VIDEO_MX2_HOSTSUPPORT
+        bool
+
+config VIDEO_MX2
+       tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
+       depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25)
+       select VIDEOBUF_DMA_CONTIG
+       select VIDEO_MX2_HOSTSUPPORT
+       ---help---
+         This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
+         Interface
+
+
 #
 # USB Multimedia device configuration
 #
@@ -1000,61 +940,6 @@ source "drivers/media/video/usbvideo/Kconfig"
 
 source "drivers/media/video/et61x251/Kconfig"
 
-config VIDEO_OVCAMCHIP
-       tristate "OmniVision Camera Chip support (DEPRECATED)"
-       depends on I2C && VIDEO_V4L1
-       default n
-       ---help---
-         This driver is DEPRECATED please use the gspca ov519 module
-         instead. Note that for the ov511 / ov518 support of the gspca module
-         you need atleast version 0.6.0 of libv4l and for the w9968cf
-         atleast version 0.6.3 of libv4l.
-
-         Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
-         This driver is intended to be used with the ov511 and w9968cf USB
-         camera drivers.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ovcamchip.
-
-config USB_W9968CF
-       tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
-       depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
-       default n
-       ---help---
-         This driver is DEPRECATED please use the gspca ov519 module
-         instead. Note that for the w9968cf support of the gspca module
-         you need atleast version 0.6.3 of libv4l.
-
-         Say Y here if you want support for cameras based on OV681 or
-         Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
-         This driver has an optional plugin, which is distributed as a
-         separate module only (released under GPL). It allows to use higher
-         resolutions and framerates, but cannot be included in the official
-         Linux kernel for performance purposes.
-
-         See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
-         To compile this driver as a module, choose M here: the
-         module will be called w9968cf.
-
-config USB_OV511
-       tristate "USB OV511 Camera support (DEPRECATED)"
-       depends on VIDEO_V4L1
-       default n
-       ---help---
-         This driver is DEPRECATED please use the gspca ov519 module
-         instead. Note that for the ov511 / ov518 support of the gspca module
-         you need atleast version 0.6.0 of libv4l.
-
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. See <file:Documentation/video4linux/ov511.txt>
-         for more information and for a list of supported cameras.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ov511.
-
 config USB_SE401
        tristate "USB SE401 Camera support"
        depends on VIDEO_V4L1
@@ -1068,25 +953,6 @@ config USB_SE401
 
 source "drivers/media/video/sn9c102/Kconfig"
 
-config USB_STV680
-       tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
-       depends on VIDEO_V4L1
-       default n
-       ---help---
-         This driver is DEPRECATED please use the gspca stv0680 module
-         instead. Note that for the gspca stv0680 module you need
-         atleast version 0.6.3 of libv4l.
-
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. This includes the Pencam line of cameras.
-         See <file:Documentation/video4linux/stv680.txt> for more information
-         and for a list of supported cameras.
-
-         To compile this driver as a module, choose M here: the
-         module will be called stv680.
-
-source "drivers/media/video/zc0301/Kconfig"
-
 source "drivers/media/video/pwc/Kconfig"
 
 config USB_ZR364XX
index cc93859d3164771fce15e54236984340b4b5f373..1051ecc602e74c07bde2e4abb55c70ca414c5494 100644 (file)
@@ -105,7 +105,6 @@ obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -127,17 +126,13 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
-obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
-obj-$(CONFIG_USB_STV680)        += stv680.o
-obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
 obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
-obj-$(CONFIG_USB_ZC0301)        += zc0301/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 
 obj-$(CONFIG_VIDEO_HDPVR)      += hdpvr/
@@ -151,6 +146,7 @@ obj-$(CONFIG_USB_S2255)             += s2255drv.o
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
 
+obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -162,8 +158,10 @@ obj-$(CONFIG_SOC_CAMERA)           += soc_camera.o soc_mediabus.o
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
 # soc-camera host drivers have to be linked after camera drivers
 obj-$(CONFIG_VIDEO_MX1)                        += mx1_camera.o
+obj-$(CONFIG_VIDEO_MX2)                        += mx2_camera.o
 obj-$(CONFIG_VIDEO_MX3)                        += mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)     += sh_mobile_csi2.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
@@ -177,7 +175,7 @@ obj-$(CONFIG_VIDEO_SAA7164)     += saa7164/
 
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 
-obj-$(CONFIG_ARCH_DAVINCI)     += davinci/
+obj-y  += davinci/
 
 obj-$(CONFIG_ARCH_OMAP)        += omap/
 
index 1573392f74bd36a2fb3d010d49238222c1f2344b..b388654d48cd6bce3859ff7601e7a7ab1abffc82 100644 (file)
@@ -126,7 +126,7 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
        v4l_bound_align_image(&mf->width, 0, 720, 2,
                              &mf->height, 0, ak881x->lines, 1, 0);
        mf->field       = V4L2_FIELD_INTERLACED;
-       mf->code        = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+       mf->code        = V4L2_MBUS_FMT_YUYV8_2X8;
        mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
 
        return 0;
@@ -136,7 +136,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
                             struct v4l2_mbus_framefmt *mf)
 {
        if (mf->field != V4L2_FIELD_INTERLACED ||
-           mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+           mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
                return -EINVAL;
 
        return ak881x_try_g_mbus_fmt(sd, mf);
@@ -148,7 +148,7 @@ static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
        if (index)
                return -EINVAL;
 
-       *code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+       *code = V4L2_MBUS_FMT_YUYV8_2X8;
        return 0;
 }
 
index 4d2623158188943cb4ff8d02c227f6e143debea5..5c7f2f7d980593795b999887b19522af42166845 100644 (file)
@@ -1,4 +1,4 @@
-au0828-objs    := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
+au0828-objs    := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828.o
 
diff --git a/drivers/media/video/au0828/au0828-vbi.c b/drivers/media/video/au0828/au0828-vbi.c
new file mode 100644 (file)
index 0000000..63f5930
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+   au0828-vbi.c - VBI driver for au0828
+
+   Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+   This work was sponsored by GetWellNetwork 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "au0828.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+       struct au0828_fh     *fh  = vq->priv_data;
+       struct au0828_dev    *dev = fh->dev;
+       unsigned long flags = 0;
+       if (in_interrupt())
+               BUG();
+
+       /* We used to wait for the buffer to finish here, but this didn't work
+          because, as we were keeping the state as VIDEOBUF_QUEUED,
+          videobuf_queue_cancel marked it as finished for us.
+          (Also, it could wedge forever if the hardware was misconfigured.)
+
+          This should be safe; by the time we get here, the buffer isn't
+          queued anymore. If we ever start marking the buffers as
+          VIDEOBUF_ACTIVE, it won't be, though.
+       */
+       spin_lock_irqsave(&dev->slock, flags);
+       if (dev->isoc_ctl.vbi_buf == buf)
+               dev->isoc_ctl.vbi_buf = NULL;
+       spin_unlock_irqrestore(&dev->slock, flags);
+
+       videobuf_vmalloc_free(&buf->vb);
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+       struct au0828_fh     *fh  = q->priv_data;
+       struct au0828_dev    *dev = fh->dev;
+
+       *size = dev->vbi_width * dev->vbi_height * 2;
+
+       if (0 == *count)
+               *count = vbibufs;
+       if (*count < 2)
+               *count = 2;
+       if (*count > 32)
+               *count = 32;
+       return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+           enum v4l2_field field)
+{
+       struct au0828_fh     *fh  = q->priv_data;
+       struct au0828_dev    *dev = fh->dev;
+       struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+       int                  rc = 0;
+
+       buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       buf->vb.width  = dev->vbi_width;
+       buf->vb.height = dev->vbi_height;
+       buf->vb.field  = field;
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               rc = videobuf_iolock(q, &buf->vb, NULL);
+               if (rc < 0)
+                       goto fail;
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+fail:
+       free_buffer(q, buf);
+       return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct au0828_buffer    *buf     = container_of(vb,
+                                                       struct au0828_buffer,
+                                                       vb);
+       struct au0828_fh        *fh      = vq->priv_data;
+       struct au0828_dev       *dev     = fh->dev;
+       struct au0828_dmaqueue  *vbiq    = &dev->vbiq;
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+       free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops au0828_vbi_qops = {
+       .buf_setup    = vbi_setup,
+       .buf_prepare  = vbi_prepare,
+       .buf_queue    = vbi_queue,
+       .buf_release  = vbi_release,
+};
index 52f25aabb6dcf769903506cad23326b674055680..7989a7ba7c4005ecea648bce20f396c198e1ece7 100644 (file)
@@ -314,6 +314,23 @@ static inline void buffer_filled(struct au0828_dev *dev,
        wake_up(&buf->vb.done);
 }
 
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+                                    struct au0828_dmaqueue *dma_q,
+                                    struct au0828_buffer *buf)
+{
+       /* Advice that buffer was filled */
+       au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+       buf->vb.state = VIDEOBUF_DONE;
+       buf->vb.field_count++;
+       do_gettimeofday(&buf->vb.ts);
+
+       dev->isoc_ctl.vbi_buf = NULL;
+
+       list_del(&buf->vb.queue);
+       wake_up(&buf->vb.done);
+}
+
 /*
  * Identify the buffer header type and properly handles
  */
@@ -327,6 +344,9 @@ static void au0828_copy_video(struct au0828_dev *dev,
        int  linesdone, currlinedone, offset, lencopy, remain;
        int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
 
+       if (len == 0)
+               return;
+
        if (dma_q->pos + len > buf->vb.size)
                len = buf->vb.size - dma_q->pos;
 
@@ -414,17 +434,98 @@ static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
        return;
 }
 
+static void au0828_copy_vbi(struct au0828_dev *dev,
+                             struct au0828_dmaqueue  *dma_q,
+                             struct au0828_buffer *buf,
+                             unsigned char *p,
+                             unsigned char *outp, unsigned long len)
+{
+       unsigned char *startwrite, *startread;
+       int bytesperline;
+       int i, j = 0;
+
+       if (dev == NULL) {
+               au0828_isocdbg("dev is null\n");
+               return;
+       }
+
+       if (dma_q == NULL) {
+               au0828_isocdbg("dma_q is null\n");
+               return;
+       }
+       if (buf == NULL)
+               return;
+       if (p == NULL) {
+               au0828_isocdbg("p is null\n");
+               return;
+       }
+       if (outp == NULL) {
+               au0828_isocdbg("outp is null\n");
+               return;
+       }
+
+       bytesperline = dev->vbi_width;
+
+       if (dma_q->pos + len > buf->vb.size)
+               len = buf->vb.size - dma_q->pos;
+
+       startread = p;
+       startwrite = outp + (dma_q->pos / 2);
+
+       /* Make sure the bottom field populates the second half of the frame */
+       if (buf->top_field == 0)
+               startwrite += bytesperline * dev->vbi_height;
+
+       for (i = 0; i < len; i += 2)
+               startwrite[j++] = startread[i+1];
+
+       dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+                                   struct au0828_buffer **buf)
+{
+       struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+       char *outp;
+
+       if (list_empty(&dma_q->active)) {
+               au0828_isocdbg("No active queue to serve\n");
+               dev->isoc_ctl.vbi_buf = NULL;
+               *buf = NULL;
+               return;
+       }
+
+       /* Get the next buffer */
+       *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+       /* Cleans up buffer - Usefull for testing for frame/URB loss */
+       outp = videobuf_to_vmalloc(&(*buf)->vb);
+       memset(outp, 0x00, (*buf)->vb.size);
+
+       dev->isoc_ctl.vbi_buf = *buf;
+
+       return;
+}
+
 /*
  * Controls the isoc copy of each urb packet
  */
 static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
 {
        struct au0828_buffer    *buf;
+       struct au0828_buffer    *vbi_buf;
        struct au0828_dmaqueue  *dma_q = urb->context;
+       struct au0828_dmaqueue  *vbi_dma_q = &dev->vbiq;
        unsigned char *outp = NULL;
+       unsigned char *vbioutp = NULL;
        int i, len = 0, rc = 1;
        unsigned char *p;
        unsigned char fbyte;
+       unsigned int vbi_field_size;
+       unsigned int remain, lencopy;
 
        if (!dev)
                return 0;
@@ -443,6 +544,10 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
        if (buf != NULL)
                outp = videobuf_to_vmalloc(&buf->vb);
 
+       vbi_buf = dev->isoc_ctl.vbi_buf;
+       if (vbi_buf != NULL)
+               vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
        for (i = 0; i < urb->number_of_packets; i++) {
                int status = urb->iso_frame_desc[i].status;
 
@@ -472,6 +577,19 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
                        au0828_isocdbg("Video frame %s\n",
                                       (fbyte & 0x40) ? "odd" : "even");
                        if (!(fbyte & 0x40)) {
+                               /* VBI */
+                               if (vbi_buf != NULL)
+                                       vbi_buffer_filled(dev,
+                                                         vbi_dma_q,
+                                                         vbi_buf);
+                               vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+                               if (vbi_buf == NULL)
+                                       vbioutp = NULL;
+                               else
+                                       vbioutp = videobuf_to_vmalloc(
+                                               &vbi_buf->vb);
+
+                               /* Video */
                                if (buf != NULL)
                                        buffer_filled(dev, dma_q, buf);
                                get_next_buf(dma_q, &buf);
@@ -488,9 +606,36 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
                                        buf->top_field = 0;
                        }
 
+                       if (vbi_buf != NULL) {
+                               if (fbyte & 0x40)
+                                       vbi_buf->top_field = 1;
+                               else
+                                       vbi_buf->top_field = 0;
+                       }
+
+                       dev->vbi_read = 0;
+                       vbi_dma_q->pos = 0;
                        dma_q->pos = 0;
                }
-               if (buf != NULL)
+
+               vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+               if (dev->vbi_read < vbi_field_size) {
+                       remain  = vbi_field_size - dev->vbi_read;
+                       if (len < remain)
+                               lencopy = len;
+                       else
+                               lencopy = remain;
+
+                       if (vbi_buf != NULL)
+                               au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+                                               vbioutp, len);
+
+                       len -= lencopy;
+                       p += lencopy;
+                       dev->vbi_read += lencopy;
+               }
+
+               if (dev->vbi_read >= vbi_field_size && buf != NULL)
                        au0828_copy_video(dev, dma_q, buf, p, outp, len);
        }
        return rc;
@@ -642,7 +787,7 @@ int au0828_analog_stream_enable(struct au0828_dev *d)
        au0828_writereg(d, 0x114, 0xa0);
        au0828_writereg(d, 0x115, 0x05);
        /* set y position */
-       au0828_writereg(d, 0x112, 0x02);
+       au0828_writereg(d, 0x112, 0x00);
        au0828_writereg(d, 0x113, 0x00);
        au0828_writereg(d, 0x116, 0xf2);
        au0828_writereg(d, 0x117, 0x00);
@@ -703,47 +848,83 @@ void au0828_analog_unregister(struct au0828_dev *dev)
 
 
 /* Usage lock check functions */
-static int res_get(struct au0828_fh *fh)
+static int res_get(struct au0828_fh *fh, unsigned int bit)
 {
-       struct au0828_dev *dev = fh->dev;
-       int              rc   = 0;
+       struct au0828_dev    *dev = fh->dev;
 
-       /* This instance already has stream_on */
-       if (fh->stream_on)
-               return rc;
+       if (fh->resources & bit)
+               /* have it already allocated */
+               return 1;
 
-       if (dev->stream_on)
-               return -EBUSY;
+       /* is it free? */
+       mutex_lock(&dev->lock);
+       if (dev->resources & bit) {
+               /* no, someone else uses it */
+               mutex_unlock(&dev->lock);
+               return 0;
+       }
+       /* it's free, grab it */
+       fh->resources  |= bit;
+       dev->resources |= bit;
+       dprintk(1, "res: get %d\n", bit);
+       mutex_unlock(&dev->lock);
+       return 1;
+}
 
-       dev->stream_on = 1;
-       fh->stream_on  = 1;
-       return rc;
+static int res_check(struct au0828_fh *fh, unsigned int bit)
+{
+       return fh->resources & bit;
 }
 
-static int res_check(struct au0828_fh *fh)
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
 {
-       return fh->stream_on;
+       return dev->resources & bit;
 }
 
-static void res_free(struct au0828_fh *fh)
+static void res_free(struct au0828_fh *fh, unsigned int bits)
 {
-       struct au0828_dev *dev = fh->dev;
+       struct au0828_dev    *dev = fh->dev;
 
-       fh->stream_on = 0;
-       dev->stream_on = 0;
+       BUG_ON((fh->resources & bits) != bits);
+
+       mutex_lock(&dev->lock);
+       fh->resources  &= ~bits;
+       dev->resources &= ~bits;
+       dprintk(1, "res: put %d\n", bits);
+       mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct au0828_fh *fh)
+{
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return AU0828_RESOURCE_VIDEO;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return AU0828_RESOURCE_VBI;
+       default:
+               BUG();
+               return 0;
+       }
 }
 
 static int au0828_v4l2_open(struct file *filp)
 {
        int ret = 0;
+       struct video_device *vdev = video_devdata(filp);
        struct au0828_dev *dev = video_drvdata(filp);
        struct au0828_fh *fh;
-       int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       int type;
 
-#ifdef VBI_IS_WORKING
-       if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER)
+       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;
-#endif
+               break;
+       default:
+               return -EINVAL;
+       }
 
        fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
        if (NULL == fh) {
@@ -781,10 +962,21 @@ static int au0828_v4l2_open(struct file *filp)
        dev->users++;
 
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
-                                   NULL, &dev->slock, fh->type,
+                                   NULL, &dev->slock,
+                                   V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
                                    sizeof(struct au0828_buffer), fh);
 
+       /* VBI Setup */
+       dev->vbi_width = 720;
+       dev->vbi_height = 1;
+       videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+                                   NULL, &dev->slock,
+                                   V4L2_BUF_TYPE_VBI_CAPTURE,
+                                   V4L2_FIELD_SEQ_TB,
+                                   sizeof(struct au0828_buffer), fh);
+
+
        return ret;
 }
 
@@ -794,17 +986,19 @@ static int au0828_v4l2_close(struct file *filp)
        struct au0828_fh *fh = filp->private_data;
        struct au0828_dev *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
-       if (res_check(fh))
-               res_free(fh);
-
-       if (dev->users == 1) {
+       if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
                videobuf_stop(&fh->vb_vidq);
-               videobuf_mmap_free(&fh->vb_vidq);
+               res_free(fh, AU0828_RESOURCE_VIDEO);
+       }
+
+       if (res_check(fh, AU0828_RESOURCE_VBI)) {
+               videobuf_stop(&fh->vb_vbiq);
+               res_free(fh, AU0828_RESOURCE_VBI);
+       }
 
+       if (dev->users == 1) {
                if (dev->dev_state & DEV_DISCONNECTED) {
                        au0828_analog_unregister(dev);
-                       mutex_unlock(&dev->lock);
                        kfree(dev);
                        return 0;
                }
@@ -823,10 +1017,11 @@ static int au0828_v4l2_close(struct file *filp)
                        printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
        }
 
+       videobuf_mmap_free(&fh->vb_vidq);
+       videobuf_mmap_free(&fh->vb_vbiq);
        kfree(fh);
        dev->users--;
        wake_up_interruptible_nr(&dev->open, 1);
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -842,16 +1037,21 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
                return rc;
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_lock(&dev->lock);
-               rc = res_get(fh);
-               mutex_unlock(&dev->lock);
-
-               if (unlikely(rc < 0))
-                       return rc;
+               if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+                       return -EBUSY;
 
                return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
                                        filp->f_flags & O_NONBLOCK);
        }
+
+       if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               if (!res_get(fh, AU0828_RESOURCE_VBI))
+                       return -EBUSY;
+
+               return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+                                           filp->f_flags & O_NONBLOCK);
+       }
+
        return 0;
 }
 
@@ -865,17 +1065,17 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-       rc = res_get(fh);
-       mutex_unlock(&dev->lock);
-
-       if (unlikely(rc < 0))
-               return POLLERR;
-
-       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+                       return POLLERR;
+               return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               if (!res_get(fh, AU0828_RESOURCE_VBI))
+                       return POLLERR;
+               return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+       } else {
                return POLLERR;
-
-       return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+       }
 }
 
 static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -888,14 +1088,10 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-       rc = res_get(fh);
-       mutex_unlock(&dev->lock);
-
-       if (unlikely(rc < 0))
-               return rc;
-
-       rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
 
        return rc;
 }
@@ -911,14 +1107,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
        maxwidth = 720;
        maxheight = 480;
 
-#ifdef VBI_IS_WORKING
-       if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-               dprintk(1, "VBI format set: to be supported!\n");
-               return 0;
-       }
-       if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-               return 0;
-#endif
        if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
@@ -999,9 +1187,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 
        /*set the device capabilities */
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-#ifdef VBI_IS_WORKING
                V4L2_CAP_VBI_CAPTURE |
-#endif
                V4L2_CAP_AUDIO |
                V4L2_CAP_READWRITE |
                V4L2_CAP_STREAMING |
@@ -1056,20 +1242,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct au0828_dev *dev = fh->dev;
        int rc;
 
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&dev->lock);
+
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                printk(KERN_INFO "%s queue busy\n", __func__);
                rc = -EBUSY;
                goto out;
        }
 
-       if (dev->stream_on && !fh->stream_on) {
-               printk(KERN_INFO "%s device in use by another fh\n", __func__);
-               rc = -EBUSY;
-               goto out;
-       }
-
-       return au0828_set_format(dev, VIDIOC_S_FMT, f);
+       rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
 out:
+       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1300,6 +1487,29 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        return 0;
 }
 
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                               struct v4l2_format *format)
+{
+       struct au0828_fh      *fh  = priv;
+       struct au0828_dev     *dev = fh->dev;
+
+       format->fmt.vbi.samples_per_line = dev->vbi_width;
+       format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+       format->fmt.vbi.offset = 0;
+       format->fmt.vbi.flags = 0;
+       format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+       format->fmt.vbi.count[0] = dev->vbi_height;
+       format->fmt.vbi.count[1] = dev->vbi_height;
+       format->fmt.vbi.start[0] = 21;
+       format->fmt.vbi.start[1] = 284;
+
+       return 0;
+}
+
 static int vidioc_g_chip_ident(struct file *file, void *priv,
               struct v4l2_dbg_chip_ident *chip)
 {
@@ -1345,25 +1555,32 @@ static int vidioc_cropcap(struct file *file, void *priv,
 static int vidioc_streamon(struct file *file, void *priv,
                           enum v4l2_buf_type type)
 {
-       struct au0828_fh *fh = priv;
-       struct au0828_dev *dev = fh->dev;
-       int rc;
+       struct au0828_fh      *fh  = priv;
+       struct au0828_dev     *dev = fh->dev;
+       int                   rc = -EINVAL;
 
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
+       if (unlikely(type != fh->type))
+               return -EINVAL;
+
+       dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+               fh, type, fh->resources, dev->resources);
+
+       if (unlikely(!res_get(fh, get_ressource(fh))))
+               return -EBUSY;
+
        if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                au0828_analog_stream_enable(dev);
                v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
        }
 
-       mutex_lock(&dev->lock);
-       rc = res_get(fh);
-
-       if (likely(rc >= 0))
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                rc = videobuf_streamon(&fh->vb_vidq);
-       mutex_unlock(&dev->lock);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_streamon(&fh->vb_vbiq);
 
        return rc;
 }
@@ -1371,38 +1588,42 @@ static int vidioc_streamon(struct file *file, void *priv,
 static int vidioc_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
-       struct au0828_fh *fh = priv;
-       struct au0828_dev *dev = fh->dev;
-       int i;
-       int ret;
-       int rc;
+       struct au0828_fh      *fh  = priv;
+       struct au0828_dev     *dev = fh->dev;
+       int                   rc;
+       int                   i;
 
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
                return -EINVAL;
        if (type != fh->type)
                return -EINVAL;
 
-       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+               fh, type, fh->resources, dev->resources);
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-               ret = au0828_stream_interrupt(dev);
-               if (ret != 0)
-                       return ret;
-       }
+               rc = au0828_stream_interrupt(dev);
+               if (rc != 0)
+                       return rc;
 
-       for (i = 0; i < AU0828_MAX_INPUT; i++) {
-               if (AUVI_INPUT(i).audio_setup == NULL)
-                       continue;
-               (AUVI_INPUT(i).audio_setup)(dev, 0);
-       }
+               for (i = 0; i < AU0828_MAX_INPUT; i++) {
+                       if (AUVI_INPUT(i).audio_setup == NULL)
+                               continue;
+                       (AUVI_INPUT(i).audio_setup)(dev, 0);
+               }
 
-       mutex_lock(&dev->lock);
-       videobuf_streamoff(&fh->vb_vidq);
-       res_free(fh);
-       mutex_unlock(&dev->lock);
+               videobuf_streamoff(&fh->vb_vidq);
+               res_free(fh, AU0828_RESOURCE_VIDEO);
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               videobuf_streamoff(&fh->vb_vbiq);
+               res_free(fh, AU0828_RESOURCE_VBI);
+       }
 
        return 0;
 }
@@ -1527,19 +1748,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
-#ifdef VBI_IS_WORKING
        .vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
-       .vidioc_try_fmt_vbi_cap     = vidioc_s_fmt_vbi_cap,
-       .vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
-#endif
+       .vidioc_s_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
        .vidioc_g_audio             = vidioc_g_audio,
        .vidioc_s_audio             = vidioc_s_audio,
        .vidioc_cropcap             = vidioc_cropcap,
-#ifdef VBI_IS_WORKING
-       .vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
-       .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-       .vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
-#endif
        .vidioc_reqbufs             = vidioc_reqbufs,
        .vidioc_querybuf            = vidioc_querybuf,
        .vidioc_qbuf                = vidioc_qbuf,
@@ -1621,8 +1834,11 @@ int au0828_analog_register(struct au0828_dev *dev,
        spin_lock_init(&dev->slock);
        mutex_init(&dev->lock);
 
+       /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
+       INIT_LIST_HEAD(&dev->vbiq.active);
+       INIT_LIST_HEAD(&dev->vbiq.queued);
 
        dev->width = NTSC_STD_W;
        dev->height = NTSC_STD_H;
@@ -1638,26 +1854,23 @@ int au0828_analog_register(struct au0828_dev *dev,
                return -ENOMEM;
        }
 
-#ifdef VBI_IS_WORKING
+       /* allocate the VBI struct */
        dev->vbi_dev = video_device_alloc();
        if (NULL == dev->vbi_dev) {
                dprintk(1, "Can't allocate vbi_device.\n");
                kfree(dev->vdev);
                return -ENOMEM;
        }
-#endif
 
        /* Fill the video capture device struct */
        *dev->vdev = au0828_video_template;
        dev->vdev->parent = &dev->usbdev->dev;
        strcpy(dev->vdev->name, "au0828a video");
 
-#ifdef VBI_IS_WORKING
        /* Setup the VBI device */
        *dev->vbi_dev = au0828_video_template;
        dev->vbi_dev->parent = &dev->usbdev->dev;
        strcpy(dev->vbi_dev->name, "au0828a vbi");
-#endif
 
        /* Register the v4l2 device */
        video_set_drvdata(dev->vdev, dev);
@@ -1669,7 +1882,6 @@ int au0828_analog_register(struct au0828_dev *dev,
                return -ENODEV;
        }
 
-#ifdef VBI_IS_WORKING
        /* Register the vbi device */
        video_set_drvdata(dev->vbi_dev, dev);
        retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
@@ -1680,7 +1892,6 @@ int au0828_analog_register(struct au0828_dev *dev,
                video_device_release(dev->vdev);
                return -ENODEV;
        }
-#endif
 
        dprintk(1, "%s completed!\n", __func__);
 
index 207f32dec6a6b38a3a3d578896d2e18026349b3d..9905bc4f5f59fa780c5b54debf6842ee7a9c42a0 100644 (file)
 
 #define AU0828_MAX_INPUT        4
 
+/* au0828 resource types (used for res_get/res_lock etc */
+#define AU0828_RESOURCE_VIDEO 0x01
+#define AU0828_RESOURCE_VBI   0x02
+
 enum au0828_itype {
        AU0828_VMUX_UNDEFINED = 0,
        AU0828_VMUX_COMPOSITE,
@@ -115,8 +119,10 @@ enum au0828_dev_state {
 
 struct au0828_fh {
        struct au0828_dev *dev;
-       unsigned int  stream_on:1;      /* Locks streams */
+       unsigned int  resources;
+
        struct videobuf_queue        vb_vidq;
+       struct videobuf_queue        vb_vbiq;
        enum v4l2_buf_type           type;
 };
 
@@ -145,7 +151,8 @@ struct au0828_usb_isoc_ctl {
        int                             tmp_buf_len;
 
                /* Stores already requested buffers */
-       struct au0828_buffer            *buf;
+       struct au0828_buffer            *buf;
+       struct au0828_buffer            *vbi_buf;
 
                /* Stores the number of received fields */
        int                             nfields;
@@ -194,11 +201,14 @@ struct au0828_dev {
        /* Analog */
        struct v4l2_device v4l2_dev;
        int users;
-       unsigned int stream_on:1;       /* Locks streams */
+       unsigned int resources; /* resources in use */
        struct video_device *vdev;
        struct video_device *vbi_dev;
        int width;
        int height;
+       int vbi_width;
+       int vbi_height;
+       u32 vbi_read;
        u32 field_size;
        u32 frame_size;
        u32 bytesperline;
@@ -219,6 +229,7 @@ struct au0828_dev {
 
        /* Isoc control struct */
        struct au0828_dmaqueue vidq;
+       struct au0828_dmaqueue vbiq;
        struct au0828_usb_isoc_ctl isoc_ctl;
        spinlock_t slock;
 
@@ -278,6 +289,9 @@ void au0828_analog_unregister(struct au0828_dev *dev);
 extern int au0828_dvb_register(struct au0828_dev *dev);
 extern void au0828_dvb_unregister(struct au0828_dev *dev);
 
+/* au0828-vbi.c */
+extern struct videobuf_queue_ops au0828_vbi_qops;
+
 #define dprintk(level, fmt, arg...)\
        do { if (au0828_debug & level)\
                printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
index c24b1c100e13fe0fb1c225950c6427da7b50db7f..0fa9f39f37a32be9303993b3e4f31835c6042ebf 100644 (file)
@@ -583,7 +583,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
 
        BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_unmap(q, dma);
+       videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(btv->c.pci,&buf->bottom);
        btcx_riscmem_free(btv->c.pci,&buf->top);
index ef1f89399983549adc9192a9f9fd79259abcdc97..58d193ff591c9b205382f7863e537c2dded81562 100644 (file)
@@ -584,7 +584,6 @@ static void cpia_disconnect(struct usb_interface *intf)
 {
        struct cam_data *cam = usb_get_intfdata(intf);
        struct usb_cpia *ucpia;
-       struct usb_device *udev;
 
        usb_set_intfdata(intf, NULL);
        if (!cam)
@@ -606,8 +605,6 @@ static void cpia_disconnect(struct usb_interface *intf)
        if (waitqueue_active(&ucpia->wq_stream))
                wake_up_interruptible(&ucpia->wq_stream);
 
-       udev = interface_to_usbdev(intf);
-
        ucpia->curbuff = ucpia->workbuff = NULL;
 
        vfree(ucpia->buffers[2]);
index 20eaf38ba95976b4a46ae7c785d4e3b63c658071..d6792405f8d381070cfe5777883866164f06cc2d 100644 (file)
@@ -1081,7 +1081,7 @@ 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 = (struct cx18_open_id *)filp->private_data;
+       struct cx18_open_id *id = filp->private_data;
        struct cx18 *cx = id->cx;
        long res;
 
index d639186f645d66bdd3434a6da4bce2cd41be8288..2014daedee8b3b827bbffc11eab4095290ce356a 100644 (file)
@@ -406,10 +406,18 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x2215,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x221d,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
        }, {
                .subvendor = 0x0070,
                .subdevice = 0x2251,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2259,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
        }, {
                .subvendor = 0x0070,
                .subdevice = 0x2291,
@@ -418,6 +426,38 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x2295,
                .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2299,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x229d,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x22f0,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x22f1,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x22f2,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x22f3,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x22f4,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x22f5,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
        }, {
                .subvendor = 0x14f1,
                .subdevice = 0x8651,
index 0dde57e96d30ac99c5adb9f8eab94f838c1b83d8..ff76f64edac1e196f8c276e543fff216669cc445 100644 (file)
@@ -1142,7 +1142,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
 
        BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb, 0, 0);
-       videobuf_dma_unmap(q, dma);
+       videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1953,8 +1953,12 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
                goto fail_irq;
        }
 
-       err = request_irq(pci_dev->irq, cx23885_irq,
-                         IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+       if (!pci_enable_msi(pci_dev))
+               err = request_irq(pci_dev->irq, cx23885_irq,
+                                 IRQF_DISABLED, dev->name, dev);
+       else
+               err = request_irq(pci_dev->irq, cx23885_irq,
+                                 IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
        if (err < 0) {
                printk(KERN_ERR "%s: can't get IRQ %d\n",
                       dev->name, pci_dev->irq);
@@ -2000,6 +2004,7 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
 
        /* unregister stuff */
        free_irq(pci_dev->irq, dev);
+       pci_disable_msi(pci_dev);
 
        cx23885_dev_unregister(dev);
        v4l2_device_unregister(v4l2_dev);
index 0a199d774d9b7473c37342f43d3629029d71c83b..3d70af283881e5203f4b7247ce3f373d16f0d840 100644 (file)
@@ -991,7 +991,7 @@ static int dvb_register(struct cx23885_tsport *port)
        ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
                                        &dev->pci->dev, adapter_nr, 0,
                                        cx23885_dvb_fe_ioctl_override);
-       if (!ret)
+       if (ret)
                return ret;
 
        /* init CI & MAC */
index 5de6ba98f7a8383cd3cb3dd7ac83ce690d1f3f29..d0b1613ede2f4e3e418eef2b772a7ccb22e5b173 100644 (file)
 
 #include <linux/input.h>
 #include <linux/slab.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 #include <media/v4l2-subdev.h>
 
 #include "cx23885.h"
 
-#define RC5_BITS               14
-#define RC5_HALF_BITS          (2*RC5_BITS)
-#define RC5_HALF_BITS_MASK     ((1 << RC5_HALF_BITS) - 1)
-
-#define RC5_START_BITS_NORMAL  0x3 /* Command range  0 -  63 */
-#define RC5_START_BITS_EXTENDED        0x2 /* Command range 64 - 127 */
-
-#define RC5_EXTENDED_COMMAND_OFFSET    64
-
 #define MODULE_NAME "cx23885"
 
-static inline unsigned int rc5_command(u32 rc5_baseband)
+static void convert_measurement(u32 x, struct ir_raw_event *y)
 {
-       return RC5_INSTR(rc5_baseband) +
-               ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED)
-                       ? RC5_EXTENDED_COMMAND_OFFSET : 0);
-}
-
-static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev)
-{
-       struct card_ir *ir_input = dev->ir_input;
-       unsigned int code, command;
-       u32 rc5;
-
-       /* Ignore codes that are too short to be valid RC-5 */
-       if (ir_input->last_bit < (RC5_HALF_BITS - 1))
-               return;
-
-       /* The library has the manchester coding backwards; XOR to adapt. */
-       code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK;
-       rc5 = ir_rc5_decode(code);
-
-       switch (RC5_START(rc5)) {
-       case RC5_START_BITS_NORMAL:
-               break;
-       case RC5_START_BITS_EXTENDED:
-               /* Don't allow if the remote only emits standard commands */
-               if (ir_input->start == RC5_START_BITS_NORMAL)
-                       return;
-               break;
-       default:
+       if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
+               y->pulse = false;
+               y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
                return;
        }
 
-       if (ir_input->addr != RC5_ADDR(rc5))
-               return;
-
-       /* Don't generate a keypress for RC-5 auto-repeated keypresses */
-       command = rc5_command(rc5);
-       if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) ||
-           command != rc5_command(ir_input->last_rc5) ||
-           /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */
-           RC5_START(ir_input->last_rc5) == 0) {
-               /* This keypress is differnet: not an auto repeat */
-               ir_input_nokey(ir_input->dev, &ir_input->ir);
-               ir_input_keydown(ir_input->dev, &ir_input->ir, command);
-       }
-       ir_input->last_rc5 = rc5;
-
-       /* Schedule when we should do the key up event: ir_input_nokey() */
-       mod_timer(&ir_input->timer_keyup,
-                 jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout));
+       y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false;
+       y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
 }
 
-static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev,
-                                              u32 ns_pulse)
+static void cx23885_input_process_measurements(struct cx23885_dev *dev,
+                                              bool overrun)
 {
-       const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */
-       struct card_ir *ir_input = dev->ir_input;
-       int i, level, quarterbits, halfbits;
-
-       if (!ir_input->active) {
-               ir_input->active = 1;
-               /* assume an initial space that we may not detect or measure */
-               ir_input->code = 0;
-               ir_input->last_bit = 0;
-       }
+       struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
+       struct ir_raw_event kernel_ir_event;
 
-       if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
-               ir_input->last_bit++; /* Account for the final space */
-               ir_input->active = 0;
-               cx23885_input_process_raw_rc5(dev);
-               return;
-       }
-
-       level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0;
-
-       /* Skip any leading space to sync to the start bit */
-       if (ir_input->last_bit == 0 && level == 0)
-               return;
-
-       /*
-        * With valid RC-5 we can get up to two consecutive half-bits in a
-        * single pulse measurment.  Experiments have shown that the duration
-        * of a half-bit can vary.  Make sure we always end up with an even
-        * number of quarter bits at the same level (mark or space).
-        */
-       ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
-       quarterbits = ns_pulse / rc5_quarterbit_ns;
-       if (quarterbits & 1)
-               quarterbits++;
-       halfbits = quarterbits / 2;
-
-       for (i = 0; i < halfbits; i++) {
-               ir_input->last_bit++;
-               ir_input->code |= (level << ir_input->last_bit);
-
-               if (ir_input->last_bit >= RC5_HALF_BITS-1) {
-                       ir_input->active = 0;
-                       cx23885_input_process_raw_rc5(dev);
-                       /*
-                        * If level is 1, a leading mark is invalid for RC5.
-                        * If level is 0, we scan past extra intial space.
-                        * Either way we don't want to reactivate collecting
-                        * marks or spaces here with any left over half-bits.
-                        */
-                       break;
-               }
-       }
-}
-
-static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev,
-                                                  bool add_eom)
-{
-       struct card_ir *ir_input = dev->ir_input;
-       struct ir_input_state *ir_input_state = &ir_input->ir;
-
-       u32 ns_pulse[RC5_HALF_BITS+1];
-       ssize_t num = 0;
+       u32 sd_ir_data[64];
+       ssize_t num;
        int count, i;
+       bool handle = false;
 
        do {
-               v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse,
-                                sizeof(ns_pulse), &num);
+               num = 0;
+               v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data,
+                                sizeof(sd_ir_data), &num);
 
                count = num / sizeof(u32);
 
-               /* Append an end of Rx seq, if the caller requested */
-               if (add_eom && count < ARRAY_SIZE(ns_pulse)) {
-                       ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
-                       count++;
+               for (i = 0; i < count; i++) {
+                       convert_measurement(sd_ir_data[i], &kernel_ir_event);
+                       ir_raw_event_store(kernel_ir->inp_dev,
+                                          &kernel_ir_event);
+                       handle = true;
                }
-
-               /* Just drain the Rx FIFO, if we're called, but not RC-5 */
-               if (ir_input_state->ir_type != IR_TYPE_RC5)
-                       continue;
-
-               for (i = 0; i < count; i++)
-                       cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]);
        } while (num != 0);
+
+       if (overrun)
+               ir_raw_event_reset(kernel_ir->inp_dev);
+       else if (handle)
+               ir_raw_event_handle(kernel_ir->inp_dev);
 }
 
 void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
@@ -230,7 +124,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
        }
 
        if (data_available)
-               cx23885_input_process_pulse_widths_rc5(dev, overrun);
+               cx23885_input_process_measurements(dev, overrun);
 
        if (overrun) {
                /* If there was a FIFO overrun, clear & restart the device */
@@ -241,34 +135,15 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
        }
 }
 
-static void cx23885_input_ir_start(struct cx23885_dev *dev)
+static int cx23885_input_ir_start(struct cx23885_dev *dev)
 {
-       struct card_ir *ir_input = dev->ir_input;
-       struct ir_input_state *ir_input_state = &ir_input->ir;
        struct v4l2_subdev_ir_parameters params;
 
        if (dev->sd_ir == NULL)
-               return;
+               return -ENODEV;
 
        atomic_set(&dev->ir_input_stopping, 0);
 
-       /* keyup timer set up, if needed */
-       switch (dev->board) {
-       case CX23885_BOARD_HAUPPAUGE_HVR1850:
-       case CX23885_BOARD_HAUPPAUGE_HVR1290:
-               setup_timer(&ir_input->timer_keyup,
-                           ir_rc5_timer_keyup, /* Not actually RC-5 specific */
-                           (unsigned long) ir_input);
-               if (ir_input_state->ir_type == IR_TYPE_RC5) {
-                       /*
-                        * RC-5 repeats a held key every
-                        * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms
-                        */
-                       ir_input->rc5_key_timeout = 115;
-               }
-               break;
-       }
-
        v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
@@ -299,11 +174,21 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev)
                break;
        }
        v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+       return 0;
+}
+
+static int cx23885_input_ir_open(void *priv)
+{
+       struct cx23885_kernel_ir *kernel_ir = priv;
+
+       if (kernel_ir->cx == NULL)
+               return -ENODEV;
+
+       return cx23885_input_ir_start(kernel_ir->cx);
 }
 
 static void cx23885_input_ir_stop(struct cx23885_dev *dev)
 {
-       struct card_ir *ir_input = dev->ir_input;
        struct v4l2_subdev_ir_parameters params;
 
        if (dev->sd_ir == NULL)
@@ -327,21 +212,26 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
        }
 
        flush_scheduled_work();
+}
 
-       switch (dev->board) {
-       case CX23885_BOARD_HAUPPAUGE_HVR1850:
-       case CX23885_BOARD_HAUPPAUGE_HVR1290:
-               del_timer_sync(&ir_input->timer_keyup);
-               break;
-       }
+static void cx23885_input_ir_close(void *priv)
+{
+       struct cx23885_kernel_ir *kernel_ir = priv;
+
+       if (kernel_ir->cx != NULL)
+               cx23885_input_ir_stop(kernel_ir->cx);
 }
 
 int cx23885_input_init(struct cx23885_dev *dev)
 {
-       struct card_ir *ir;
-       struct input_dev *input_dev;
-       char *ir_codes = NULL;
-       int ir_type, ir_addr, ir_start;
+       struct cx23885_kernel_ir *kernel_ir;
+       struct input_dev *inp_dev;
+       struct ir_dev_props *props;
+
+       char *rc_map;
+       enum rc_driver_type driver_type;
+       unsigned long allowed_protos;
+
        int ret;
 
        /*
@@ -354,53 +244,59 @@ int cx23885_input_init(struct cx23885_dev *dev)
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
-               /* Parameters for the grey Hauppauge remote for the HVR-1850 */
-               ir_codes = RC_MAP_HAUPPAUGE_NEW;
-               ir_type = IR_TYPE_RC5;
-               ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */
-               ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */
+               /* Integrated CX23888 IR controller */
+               driver_type = RC_DRIVER_IR_RAW;
+               allowed_protos = IR_TYPE_ALL;
+               /* The grey Hauppauge RC-5 remote */
+               rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
                break;
-       }
-       if (ir_codes == NULL)
+       default:
                return -ENODEV;
-
-       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ir || !input_dev) {
-               ret = -ENOMEM;
-               goto err_out_free;
        }
 
-       ir->dev = input_dev;
-       ir->addr = ir_addr;
-       ir->start = ir_start;
+       /* cx23885 board instance kernel IR state */
+       kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
+       if (kernel_ir == NULL)
+               return -ENOMEM;
 
-       /* init input device */
-       snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)",
-                cx23885_boards[dev->board].name);
-       snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci));
+       kernel_ir->cx = dev;
+       kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
+                                   cx23885_boards[dev->board].name);
+       kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
+                                   pci_name(dev->pci));
 
-       ret = ir_input_init(input_dev, &ir->ir, ir_type);
-       if (ret < 0)
+       /* input device */
+       inp_dev = input_allocate_device();
+       if (inp_dev == NULL) {
+               ret = -ENOMEM;
                goto err_out_free;
+       }
 
-       input_dev->name = ir->name;
-       input_dev->phys = ir->phys;
-       input_dev->id.bustype = BUS_PCI;
-       input_dev->id.version = 1;
+       kernel_ir->inp_dev = inp_dev;
+       inp_dev->name = kernel_ir->name;
+       inp_dev->phys = kernel_ir->phys;
+       inp_dev->id.bustype = BUS_PCI;
+       inp_dev->id.version = 1;
        if (dev->pci->subsystem_vendor) {
-               input_dev->id.vendor  = dev->pci->subsystem_vendor;
-               input_dev->id.product = dev->pci->subsystem_device;
+               inp_dev->id.vendor  = dev->pci->subsystem_vendor;
+               inp_dev->id.product = dev->pci->subsystem_device;
        } else {
-               input_dev->id.vendor  = dev->pci->vendor;
-               input_dev->id.product = dev->pci->device;
+               inp_dev->id.vendor  = dev->pci->vendor;
+               inp_dev->id.product = dev->pci->device;
        }
-       input_dev->dev.parent = &dev->pci->dev;
-
-       dev->ir_input = ir;
-       cx23885_input_ir_start(dev);
-
-       ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME);
+       inp_dev->dev.parent = &dev->pci->dev;
+
+       /* kernel ir device properties */
+       props = &kernel_ir->props;
+       props->driver_type = driver_type;
+       props->allowed_protos = allowed_protos;
+       props->priv = kernel_ir;
+       props->open = cx23885_input_ir_open;
+       props->close = cx23885_input_ir_close;
+
+       /* Go */
+       dev->kernel_ir = kernel_ir;
+       ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME);
        if (ret)
                goto err_out_stop;
 
@@ -408,9 +304,12 @@ int cx23885_input_init(struct cx23885_dev *dev)
 
 err_out_stop:
        cx23885_input_ir_stop(dev);
-       dev->ir_input = NULL;
+       dev->kernel_ir = NULL;
+       /* TODO: double check clean-up of kernel_ir->inp_dev */
 err_out_free:
-       kfree(ir);
+       kfree(kernel_ir->phys);
+       kfree(kernel_ir->name);
+       kfree(kernel_ir);
        return ret;
 }
 
@@ -419,9 +318,11 @@ void cx23885_input_fini(struct cx23885_dev *dev)
        /* Always stop the IR hardware from generating interrupts */
        cx23885_input_ir_stop(dev);
 
-       if (dev->ir_input == NULL)
+       if (dev->kernel_ir == NULL)
                return;
-       ir_input_unregister(dev->ir_input->dev);
-       kfree(dev->ir_input);
-       dev->ir_input = NULL;
+       ir_input_unregister(dev->kernel_ir->inp_dev);
+       kfree(dev->kernel_ir->phys);
+       kfree(dev->kernel_ir->name);
+       kfree(dev->kernel_ir);
+       dev->kernel_ir = NULL;
 }
index 9a677eb080af4efb3d58d1dccd63a166a1ef2cdc..6ceabd4fba07ba024bbef9b7273eda93972fcf32 100644 (file)
@@ -53,7 +53,7 @@ void cx23885_ir_rx_work_handler(struct work_struct *work)
        if (events == 0)
                return;
 
-       if (dev->ir_input)
+       if (dev->kernel_ir)
                cx23885_input_rx_work_handler(dev, events);
 }
 
index 8d6a55e54ee7da7b12350a65bedfb135fd62ae1a..a33f2b71467bcc29e7e701d5d26ee6dde8a4a21c 100644 (file)
@@ -30,6 +30,7 @@
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
+#include <media/ir-core.h>
 
 #include "btcx-risc.h"
 #include "cx23885-reg.h"
@@ -304,6 +305,15 @@ struct cx23885_tsport {
        void                       *port_priv;
 };
 
+struct cx23885_kernel_ir {
+       struct cx23885_dev      *cx;
+       char                    *name;
+       char                    *phys;
+
+       struct input_dev        *inp_dev;
+       struct ir_dev_props     props;
+};
+
 struct cx23885_dev {
        atomic_t                   refcount;
        struct v4l2_device         v4l2_dev;
@@ -363,7 +373,7 @@ struct cx23885_dev {
        struct work_struct         ir_tx_work;
        unsigned long              ir_tx_notifications;
 
-       struct card_ir             *ir_input;
+       struct cx23885_kernel_ir   *kernel_ir;
        atomic_t                   ir_input_stopping;
 
        /* V4l */
index 33082c96745ed91d9eb23aceba34562cc66e4c4a..4f383cdf5296f3bd920a257a4e80a50519992319 100644 (file)
        Data type declarations - Can be moded to a header file later
  ****************************************************************************/
 
+struct cx88_audio_buffer {
+       unsigned int               bpl;
+       struct btcx_riscmem        risc;
+       struct videobuf_dmabuf     dma;
+};
+
 struct cx88_audio_dev {
        struct cx88_core           *core;
        struct cx88_dmaqueue       q;
@@ -75,7 +81,7 @@ struct cx88_audio_dev {
 
        struct videobuf_dmabuf     *dma_risc;
 
-       struct cx88_buffer         *buf;
+       struct cx88_audio_buffer   *buf;
 
        struct snd_pcm_substream   *substream;
 };
@@ -123,7 +129,7 @@ MODULE_PARM_DESC(debug,"enable debug messages");
 
 static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
 {
-       struct cx88_buffer   *buf = chip->buf;
+       struct cx88_audio_buffer *buf = chip->buf;
        struct cx88_core *core=chip->core;
        struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
 
@@ -283,7 +289,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
        BUG_ON(!chip->dma_size);
 
        dprintk(2,"Freeing buffer\n");
-       videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+       videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
        videobuf_dma_free(chip->dma_risc);
        btcx_riscmem_free(chip->pci,&chip->buf->risc);
        kfree(chip->buf);
@@ -376,7 +382,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
        snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
        struct videobuf_dmabuf *dma;
 
-       struct cx88_buffer *buf;
+       struct cx88_audio_buffer *buf;
        int ret;
 
        if (substream->runtime->dma_area) {
@@ -391,30 +397,25 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
        BUG_ON(!chip->dma_size);
        BUG_ON(chip->num_periods & (chip->num_periods-1));
 
-       buf = videobuf_sg_alloc(sizeof(*buf));
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
        if (NULL == buf)
                return -ENOMEM;
 
-       buf->vb.memory = V4L2_MEMORY_MMAP;
-       buf->vb.field  = V4L2_FIELD_NONE;
-       buf->vb.width  = chip->period_size;
-       buf->bpl       = chip->period_size;
-       buf->vb.height = chip->num_periods;
-       buf->vb.size   = chip->dma_size;
+       buf->bpl = chip->period_size;
 
-       dma = videobuf_to_dma(&buf->vb);
+       dma = &buf->dma;
        videobuf_dma_init(dma);
        ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
-                       (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+                       (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
        if (ret < 0)
                goto error;
 
-       ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+       ret = videobuf_dma_map(&chip->pci->dev, dma);
        if (ret < 0)
                goto error;
 
        ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
-                                  buf->vb.width, buf->vb.height, 1);
+                                  chip->period_size, chip->num_periods, 1);
        if (ret < 0)
                goto error;
 
@@ -422,12 +423,10 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
        buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
        buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 
-       buf->vb.state = VIDEOBUF_PREPARED;
-
        chip->buf = buf;
        chip->dma_risc = dma;
 
-       substream->runtime->dma_area = chip->dma_risc->vmalloc;
+       substream->runtime->dma_area = chip->dma_risc->vaddr;
        substream->runtime->dma_bytes = chip->dma_size;
        substream->runtime->dma_addr = 0;
        return 0;
@@ -740,7 +739,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
 
        pci_set_master(pci);
 
-       chip = (snd_cx88_card_t *) card->private_data;
+       chip = card->private_data;
 
        core = cx88_core_get(pci);
        if (NULL == core) {
index 2918a6e38fe8e5fa9039a0e088c59024443e7f71..e8416b76da6708fd27451e5674597fce91dc963a 100644 (file)
@@ -45,6 +45,10 @@ static unsigned int latency = UNSET;
 module_param(latency,int,0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
 
+static int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(latency, "Disable IR support");
+
 #define info_printk(core, fmt, arg...) \
        printk(KERN_INFO "%s: " fmt, core->name , ## arg)
 
@@ -3498,7 +3502,10 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
        }
 
        cx88_card_setup(core);
-       cx88_ir_init(core, pci);
+       if (!disable_ir) {
+               cx88_i2c_init_ir(core);
+               cx88_ir_init(core, pci);
+       }
 
        return core;
 }
index 8b21457111b18dda2c656872fed49108db37dd4a..85eb266fb351fc9f9161ea7d5dcf62b5aed32843 100644 (file)
@@ -218,7 +218,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
 
        BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_unmap(q, dma);
+       videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
index fb39f11845583a86dcb463745d66d498bc873efe..375ad53f796124637ed4053040166b739f74d99e 100644 (file)
@@ -181,6 +181,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
        } else
                printk("%s: i2c register FAILED\n", core->name);
 
+       return core->i2c_rc;
+}
+
+void cx88_i2c_init_ir(struct cx88_core *core)
+{
        /* Instantiate the IR receiver device, if present */
        if (0 == core->i2c_rc) {
                struct i2c_board_info info;
@@ -207,7 +212,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
                        }
                }
        }
-       return core->i2c_rc;
 }
 
 /* ----------------------------------------------------------------------- */
index e185289e446cf5ec432e7147241bcf0120fdc96b..eccc5e49a3505f5bb057c5a761e59b578cb78b50 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 
 #include "cx88.h"
+#include <media/ir-core.h>
 #include <media/ir-common.h>
 
 #define MODULE_NAME "cx88xx"
@@ -39,8 +40,8 @@
 struct cx88_IR {
        struct cx88_core *core;
        struct input_dev *input;
-       struct ir_input_state ir;
        struct ir_dev_props props;
+       u64 ir_type;
 
        int users;
 
@@ -51,7 +52,6 @@ struct cx88_IR {
        u32 sampling;
        u32 samples[16];
        int scount;
-       unsigned long release;
 
        /* poll external decoder */
        int polling;
@@ -125,29 +125,21 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 
                data = (data << 4) | ((gpio_key & 0xf0) >> 4);
 
-               ir_input_keydown(ir->input, &ir->ir, data);
-               ir_input_nokey(ir->input, &ir->ir);
+               ir_keydown(ir->input, data, 0);
 
        } else if (ir->mask_keydown) {
                /* bit set on keydown */
-               if (gpio & ir->mask_keydown) {
-                       ir_input_keydown(ir->input, &ir->ir, data);
-               } else {
-                       ir_input_nokey(ir->input, &ir->ir);
-               }
+               if (gpio & ir->mask_keydown)
+                       ir_keydown(ir->input, data, 0);
 
        } else if (ir->mask_keyup) {
                /* bit cleared on keydown */
-               if (0 == (gpio & ir->mask_keyup)) {
-                       ir_input_keydown(ir->input, &ir->ir, data);
-               } else {
-                       ir_input_nokey(ir->input, &ir->ir);
-               }
+               if (0 == (gpio & ir->mask_keyup))
+                       ir_keydown(ir->input, data, 0);
 
        } else {
                /* can't distinguish keydown/up :-/ */
-               ir_input_keydown(ir->input, &ir->ir, data);
-               ir_input_nokey(ir->input, &ir->ir);
+               ir_keydown(ir->input, data, 0);
        }
 }
 
@@ -439,9 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
        snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
 
-       err = ir_input_init(input_dev, &ir->ir, ir_type);
-       if (err < 0)
-               goto err_out_free;
+       ir->ir_type = ir_type;
 
        input_dev->name = ir->name;
        input_dev->phys = ir->phys;
@@ -516,8 +506,6 @@ void cx88_ir_irq(struct cx88_core *core)
        }
        if (!ir->scount) {
                /* nothing to sample */
-               if (ir->ir.keypressed && time_after(jiffies, ir->release))
-                       ir_input_nokey(ir->input, &ir->ir);
                return;
        }
 
@@ -553,7 +541,7 @@ void cx88_ir_irq(struct cx88_core *core)
 
                if (ircode == 0) { /* key still pressed */
                        ir_dprintk("pulse distance decoded repeat code\n");
-                       ir->release = jiffies + msecs_to_jiffies(120);
+                       ir_repeat(ir->input);
                        break;
                }
 
@@ -567,10 +555,8 @@ void cx88_ir_irq(struct cx88_core *core)
                        break;
                }
 
-               ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f);
-
-               ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f);
-               ir->release = jiffies + msecs_to_jiffies(120);
+               ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff);
+               ir_keydown(ir->input, (ircode >> 16) & 0xff, 0);
                break;
        case CX88_BOARD_HAUPPAUGE:
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
@@ -606,16 +592,16 @@ void cx88_ir_irq(struct cx88_core *core)
                if ( dev != 0x1e && dev != 0x1f )
                        /* not a hauppauge remote */
                        break;
-               ir_input_keydown(ir->input, &ir->ir, code);
-               ir->release = jiffies + msecs_to_jiffies(120);
+               ir_keydown(ir->input, code, toggle);
                break;
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
                if ((ircode & 0xfffff000) != 0x3000)
                        break;
-               ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f);
-               ir->release = jiffies + msecs_to_jiffies(120);
+               /* Note: bit 0x800 being the toggle is assumed, not checked
+                  with real hardware  */
+               ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0);
                break;
        }
 
index bdb03d33653610efbe4f69a5b613c4629620e2b1..33d161a1172544f38988f1aab0f7c02d173344c5 100644 (file)
@@ -636,6 +636,7 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
 /* cx88-i2c.c                                                  */
 
 extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
 
 
 /* ----------------------------------------------------------- */
index 0f505086774c73b45e94636fb0fc3b2182ccb49e..5b176bd7afdbffea7eb94f52bcb50d07b6c74170 100644 (file)
@@ -706,16 +706,11 @@ static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg
        switch (cmd) {
 
        case IOCTL_DAB_BULK:
-               pbulk = kmalloc(sizeof (bulk_transfer_t), GFP_KERNEL);
+               pbulk = memdup_user((void __user *)arg,
+                                   sizeof(bulk_transfer_t));
 
-               if (!pbulk) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
-                       ret = -EFAULT;
-                       kfree (pbulk);
+               if (IS_ERR(pbulk)) {
+                       ret = PTR_ERR(pbulk);
                        break;
                }
 
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
new file mode 100644 (file)
index 0000000..6b19540
--- /dev/null
@@ -0,0 +1,93 @@
+config DISPLAY_DAVINCI_DM646X_EVM
+       tristate "DM646x EVM Video Display"
+       depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+       select VIDEOBUF_DMA_CONTIG
+       select VIDEO_DAVINCI_VPIF
+       select VIDEO_ADV7343
+       select VIDEO_THS7303
+       help
+         Support for DM6467 based display device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vpif_display.
+
+config CAPTURE_DAVINCI_DM646X_EVM
+       tristate "DM646x EVM Video Capture"
+       depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+       select VIDEOBUF_DMA_CONTIG
+       select VIDEO_DAVINCI_VPIF
+       help
+         Support for DM6467 based capture device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vpif_capture.
+
+config VIDEO_DAVINCI_VPIF
+       tristate "DaVinci VPIF Driver"
+       depends on DISPLAY_DAVINCI_DM646X_EVM
+       help
+         Support for DaVinci VPIF Driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vpif.
+
+config VIDEO_VPSS_SYSTEM
+       tristate "VPSS System module driver"
+       depends on ARCH_DAVINCI
+       help
+         Support for vpss system module for video driver
+
+config VIDEO_VPFE_CAPTURE
+       tristate "VPFE Video Capture Driver"
+       depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+       select VIDEOBUF_DMA_CONTIG
+       help
+         Support for DMx/AMx VPFE based frame grabber. This is the
+         common V4L2 module for following DMx/AMx SoCs from Texas
+         Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+       tristate "DM6446 CCDC HW module"
+       depends on VIDEO_VPFE_CAPTURE
+       select VIDEO_VPSS_SYSTEM
+       default y
+       help
+          Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+          with decoder modules such as TVP5146 over BT656 or
+          sensor module such as MT9T001 over a raw interface. This
+          module configures the interface and CCDC/ISIF to do
+          video frame capture from slave decoders.
+
+          To compile this driver as a module, choose M here: the
+          module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+       tristate "DM355 CCDC HW module"
+       depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+       select VIDEO_VPSS_SYSTEM
+       default y
+       help
+          Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+          with decoder modules such as TVP5146 over BT656 or
+          sensor module such as MT9T001 over a raw interface. This
+          module configures the interface and CCDC/ISIF to do
+          video frame capture from a slave decoders
+
+          To compile this driver as a module, choose M here: the
+          module will be called vpfe.
+
+config VIDEO_ISIF
+       tristate "ISIF HW module"
+       depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+       select VIDEO_VPSS_SYSTEM
+       default y
+       help
+          Enables ISIF hw module. This is the hardware module for
+          configuring ISIF in VPFE to capture Raw Bayer RGB data  from
+          a image sensor or YUV data from a YUV source.
+
+          To compile this driver as a module, choose M here: the
+          module will be called vpfe.
index 3a4fd85145117818328dcacd9577d5017176c711..ffbe544e30f4cc868b213ab2e614eca48b933280 100644 (file)
@@ -158,6 +158,22 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
        { -1,                   -1,     -1,             -1},
 };
 
+/*
+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * EM_GPIO_0 - currently unknown
+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
+ * EM_GPIO_2 - currently unknown
+ * EM_GPIO_3 - currently unknown
+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset)
+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset)
+ * EM_GPIO_6 - currently unknown
+ * EM_GPIO_7 - currently unknown
+ */
+static struct em28xx_reg_seq kworld_a340_digital[] = {
+       {EM28XX_R08_GPIO,       0x6d,           ~EM_GPIO_4,     10},
+       { -1,                   -1,             -1,             -1},
+};
+
 /* Pinnacle Hybrid Pro eb1a:2881 */
 static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
        {EM28XX_R08_GPIO,       0xfd,   ~EM_GPIO_4,     10},
@@ -1667,6 +1683,16 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_gpio    = reddo_dvb_c_usb_box,
                .has_dvb       = 1,
        },
+       /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
+        * initially as the KWorld PlusTV 340U, then as the UB435-Q.
+        * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
+       [EM2870_BOARD_KWORLD_A340] = {
+               .name       = "KWorld PlusTV 340U or UB435-Q (ATSC)",
+               .tuner_type = TUNER_ABSENT,     /* Digital-only TDA18271HD */
+               .has_dvb    = 1,
+               .dvb_gpio   = kworld_a340_digital,
+               .tuner_gpio = default_tuner_gpio,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1788,6 +1814,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
        { USB_DEVICE(0xeb1a, 0x50a6),
                        .driver_info = EM2860_BOARD_GADMEI_UTV330 },
+       { USB_DEVICE(0x1b80, 0xa340),
+                       .driver_info = EM2870_BOARD_KWORLD_A340 },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
index cf1d8c3655fc0ac7c44ac695fda8212044d1daa4..3ac8d3025fea0b27a87f6f78aa74e86d580c8df9 100644 (file)
 #include "tuner-simple.h"
 
 #include "lgdt330x.h"
+#include "lgdt3305.h"
 #include "zl10353.h"
 #include "s5h1409.h"
 #include "mt352.h"
 #include "mt352_priv.h" /* FIXME */
 #include "tda1002x.h"
+#include "tda18271.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -231,6 +233,18 @@ static struct lgdt330x_config em2880_lgdt3303_dev = {
        .demod_chip = LGDT3303,
 };
 
+static struct lgdt3305_config em2870_lgdt3304_dev = {
+       .i2c_addr           = 0x0e,
+       .demod_chip         = LGDT3304,
+       .spectral_inversion = 1,
+       .deny_i2c_rptr      = 1,
+       .mpeg_mode          = LGDT3305_MPEG_PARALLEL,
+       .tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .vsb_if_khz         = 3250,
+       .qam_if_khz         = 4000,
+};
+
 static struct zl10353_config em28xx_zl10353_with_xc3028 = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
@@ -247,6 +261,17 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 };
 
+static struct tda18271_std_map kworld_a340_std_map = {
+       .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 0,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 1,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_a340_config = {
+       .std_map           = &kworld_a340_std_map,
+};
+
 static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
        .demod_address = (0x1e >> 1),
        .no_tuner = 1,
@@ -572,6 +597,14 @@ static int dvb_init(struct em28xx *dev)
                        }
                }
                break;
+       case EM2870_BOARD_KWORLD_A340:
+               dvb->frontend = dvb_attach(lgdt3305_attach,
+                                          &em2870_lgdt3304_dev,
+                                          &dev->i2c_adap);
+               if (dvb->frontend != NULL)
+                       dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+                                  &dev->i2c_adap, &kworld_a340_config);
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
index 5c3fd9411b1fcc25967482ffdc5e3c0e8affb056..6759cd5570dd2c720f9a13126e4aab2cf3353003 100644 (file)
@@ -65,17 +65,14 @@ struct em28xx_ir_poll_result {
 struct em28xx_IR {
        struct em28xx *dev;
        struct input_dev *input;
-       struct ir_input_state ir;
        char name[32];
        char phys[32];
 
        /* poll external decoder */
        int polling;
        struct delayed_work work;
-       unsigned int last_toggle:1;
        unsigned int full_code:1;
        unsigned int last_readcount;
-       unsigned int repeat_interval;
 
        int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
 
@@ -291,67 +288,39 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
 static void em28xx_ir_handle_key(struct em28xx_IR *ir)
 {
        int result;
-       int do_sendkey = 0;
        struct em28xx_ir_poll_result poll_result;
 
        /* read the registers containing the IR status */
        result = ir->get_key(ir, &poll_result);
-       if (result < 0) {
+       if (unlikely(result < 0)) {
                dprintk("ir->get_key() failed %d\n", result);
                return;
        }
 
-       dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n",
-               poll_result.toggle_bit, poll_result.read_count,
-               ir->last_readcount, poll_result.rc_address,
-               poll_result.rc_data[0]);
-
-       if (ir->dev->chip_id == CHIP_ID_EM2874) {
-               /* The em2874 clears the readcount field every time the
-                  register is read.  The em2860/2880 datasheet says that it
-                  is supposed to clear the readcount, but it doesn't.  So with
-                  the em2874, we are looking for a non-zero read count as
-                  opposed to a readcount that is incrementing */
-               ir->last_readcount = 0;
-       }
-
-       if (poll_result.read_count == 0) {
-               /* The button has not been pressed since the last read */
-       } else if (ir->last_toggle != poll_result.toggle_bit) {
-               /* A button has been pressed */
-               dprintk("button has been pressed\n");
-               ir->last_toggle = poll_result.toggle_bit;
-               ir->repeat_interval = 0;
-               do_sendkey = 1;
-       } else if (poll_result.toggle_bit == ir->last_toggle &&
-                  poll_result.read_count > 0 &&
-                  poll_result.read_count != ir->last_readcount) {
-               /* The button is still being held down */
-               dprintk("button being held down\n");
-
-               /* Debouncer for first keypress */
-               if (ir->repeat_interval++ > 9) {
-                       /* Start repeating after 1 second */
-                       do_sendkey = 1;
-               }
-       }
-
-       if (do_sendkey) {
-               dprintk("sending keypress\n");
-
+       if (unlikely(poll_result.read_count != ir->last_readcount)) {
+               dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
+                       poll_result.toggle_bit, poll_result.read_count,
+                       poll_result.rc_address, poll_result.rc_data[0]);
                if (ir->full_code)
-                       ir_input_keydown(ir->input, &ir->ir,
-                                        poll_result.rc_address << 8 |
-                                        poll_result.rc_data[0]);
+                       ir_keydown(ir->input,
+                                  poll_result.rc_address << 8 |
+                                  poll_result.rc_data[0],
+                                  poll_result.toggle_bit);
                else
-                       ir_input_keydown(ir->input, &ir->ir,
-                                        poll_result.rc_data[0]);
-
-               ir_input_nokey(ir->input, &ir->ir);
+                       ir_keydown(ir->input,
+                                  poll_result.rc_data[0],
+                                  poll_result.toggle_bit);
+
+               if (ir->dev->chip_id == CHIP_ID_EM2874)
+                       /* The em2874 clears the readcount field every time the
+                          register is read.  The em2860/2880 datasheet says that it
+                          is supposed to clear the readcount, but it doesn't.  So with
+                          the em2874, we are looking for a non-zero read count as
+                          opposed to a readcount that is incrementing */
+                       ir->last_readcount = 0;
+               else
+                       ir->last_readcount = poll_result.read_count;
        }
-
-       ir->last_readcount = poll_result.read_count;
-       return;
 }
 
 static void em28xx_ir_work(struct work_struct *work)
@@ -466,11 +435,6 @@ int em28xx_ir_init(struct em28xx *dev)
        usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
        strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-       /* Set IR protocol */
-       err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
-       if (err < 0)
-               goto err_out_free;
-
        input_dev->name = ir->name;
        input_dev->phys = ir->phys;
        input_dev->id.bustype = BUS_USB;
index 20090e34173a617c8cd6030124948f2110533917..7b9ec6e493e4ee43b5534326f6b0c43ed126df7f 100644 (file)
@@ -654,12 +654,12 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
                }
 
                if (buf != NULL && dev->capture_type == 2) {
-                       if (len > 4 && p[0] == 0x88 && p[1] == 0x88 &&
+                       if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
                            p[2] == 0x88 && p[3] == 0x88) {
                                p += 4;
                                len -= 4;
                        }
-                       if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) {
+                       if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
                                em28xx_isocdbg("Video frame %d, len=%i, %s\n",
                                               p[2], len, (p[2] & 1) ?
                                               "odd" : "even");
index b252d1b1b2a7133c5a3fdc06dbc7fefd0f7e2d56..1c61a6b65d2817e1f840b7df28be5ff9bc5e4a16 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
+#include <media/ir-core.h>
 #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
 #include <media/videobuf-dvb.h>
 #endif
 #define EM2870_BOARD_REDDO_DVB_C_USB_BOX          73
 #define EM2800_BOARD_VC211A                      74
 #define EM2882_BOARD_DIKOM_DK300                 75
+#define EM2870_BOARD_KWORLD_A340                 76
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
new file mode 100644 (file)
index 0000000..8f1c94f
--- /dev/null
@@ -0,0 +1,1632 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *  Freescale VIU video driver
+ *
+ *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ *          Porting to 2.6.35 by DENX Software Engineering,
+ *          Anatolij Gustschin <agust@denx.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#define DRV_NAME               "fsl_viu"
+#define VIU_MAJOR_VERSION      0
+#define VIU_MINOR_VERSION      5
+#define VIU_RELEASE            0
+#define VIU_VERSION            KERNEL_VERSION(VIU_MAJOR_VERSION, \
+                                              VIU_MINOR_VERSION, \
+                                              VIU_RELEASE)
+
+#define BUFFER_TIMEOUT         msecs_to_jiffies(500)  /* 0.5 seconds */
+
+#define        VIU_VID_MEM_LIMIT       4       /* Video memory limit, in Mb */
+
+/* I2C address of video decoder chip is 0x4A */
+#define VIU_VIDEO_DECODER_ADDR 0x25
+
+/* supported controls */
+static struct v4l2_queryctrl viu_qctrl[] = {
+       {
+               .id            = V4L2_CID_BRIGHTNESS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 127,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_CONTRAST,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 0x1,
+               .default_value = 0x10,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_SATURATION,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 0x1,
+               .default_value = 127,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_HUE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Hue",
+               .minimum       = -128,
+               .maximum       = 127,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = 0,
+       }
+};
+
+static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
+
+static int info_level;
+
+#define dprintk(level, fmt, arg...)                                    \
+       do {                                                            \
+               if (level <= info_level)                                \
+                       printk(KERN_DEBUG "viu: " fmt , ## arg);        \
+       } while (0)
+
+/*
+ * Basic structures
+ */
+struct viu_fmt {
+       char  name[32];
+       u32   fourcc;           /* v4l2 format id */
+       u32   pixelformat;
+       int   depth;
+};
+
+static struct viu_fmt formats[] = {
+       {
+               .name           = "RGB-16 (5/B-6/G-5/R)",
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .depth          = 16,
+       }, {
+               .name           = "RGB-32 (A-R-G-B)",
+               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .pixelformat    = V4L2_PIX_FMT_RGB32,
+               .depth          = 32,
+       }
+};
+
+struct viu_dev;
+struct viu_buf;
+
+/* buffer for one video frame */
+struct viu_buf {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+       struct viu_fmt *fmt;
+};
+
+struct viu_dmaqueue {
+       struct viu_dev          *dev;
+       struct list_head        active;
+       struct list_head        queued;
+       struct timer_list       timeout;
+};
+
+struct viu_status {
+       u32 field_irq;
+       u32 vsync_irq;
+       u32 hsync_irq;
+       u32 vstart_irq;
+       u32 dma_end_irq;
+       u32 error_irq;
+};
+
+struct viu_reg {
+       u32 status_cfg;
+       u32 luminance;
+       u32 chroma_r;
+       u32 chroma_g;
+       u32 chroma_b;
+       u32 field_base_addr;
+       u32 dma_inc;
+       u32 picture_count;
+       u32 req_alarm;
+       u32 alpha;
+} __attribute__ ((packed));
+
+struct viu_dev {
+       struct v4l2_device      v4l2_dev;
+       struct mutex            lock;
+       spinlock_t              slock;
+       int                     users;
+
+       struct device           *dev;
+       /* various device info */
+       struct video_device     *vdev;
+       struct viu_dmaqueue     vidq;
+       enum v4l2_field         capfield;
+       int                     field;
+       int                     first;
+       int                     dma_done;
+
+       /* Hardware register area */
+       struct viu_reg          *vr;
+
+       /* Interrupt vector */
+       int                     irq;
+       struct viu_status       irqs;
+
+       /* video overlay */
+       struct v4l2_framebuffer ovbuf;
+       struct viu_fmt          *ovfmt;
+       unsigned int            ovenable;
+       enum v4l2_field         ovfield;
+
+       /* crop */
+       struct v4l2_rect        crop_current;
+
+       /* clock pointer */
+       struct clk              *clk;
+
+       /* decoder */
+       struct v4l2_subdev      *decoder;
+};
+
+struct viu_fh {
+       struct viu_dev          *dev;
+
+       /* video capture */
+       struct videobuf_queue   vb_vidq;
+       spinlock_t              vbq_lock; /* spinlock for the videobuf queue */
+
+       /* video overlay */
+       struct v4l2_window      win;
+       struct v4l2_clip        clips[1];
+
+       /* video capture */
+       struct viu_fmt          *fmt;
+       int                     width, height, sizeimage;
+       enum v4l2_buf_type      type;
+};
+
+static struct viu_reg reg_val;
+
+/*
+ * Macro definitions of VIU registers
+ */
+
+/* STATUS_CONFIG register */
+enum status_config {
+       SOFT_RST                = 1 << 0,
+
+       ERR_MASK                = 0x0f << 4,    /* Error code mask */
+       ERR_NO                  = 0x00,         /* No error */
+       ERR_DMA_V               = 0x01 << 4,    /* DMA in vertical active */
+       ERR_DMA_VB              = 0x02 << 4,    /* DMA in vertical blanking */
+       ERR_LINE_TOO_LONG       = 0x04 << 4,    /* Line too long */
+       ERR_TOO_MANG_LINES      = 0x05 << 4,    /* Too many lines in field */
+       ERR_LINE_TOO_SHORT      = 0x06 << 4,    /* Line too short */
+       ERR_NOT_ENOUGH_LINE     = 0x07 << 4,    /* Not enough lines in field */
+       ERR_FIFO_OVERFLOW       = 0x08 << 4,    /* FIFO overflow */
+       ERR_FIFO_UNDERFLOW      = 0x09 << 4,    /* FIFO underflow */
+       ERR_1bit_ECC            = 0x0a << 4,    /* One bit ECC error */
+       ERR_MORE_ECC            = 0x0b << 4,    /* Two/more bits ECC error */
+
+       INT_FIELD_EN            = 0x01 << 8,    /* Enable field interrupt */
+       INT_VSYNC_EN            = 0x01 << 9,    /* Enable vsync interrupt */
+       INT_HSYNC_EN            = 0x01 << 10,   /* Enable hsync interrupt */
+       INT_VSTART_EN           = 0x01 << 11,   /* Enable vstart interrupt */
+       INT_DMA_END_EN          = 0x01 << 12,   /* Enable DMA end interrupt */
+       INT_ERROR_EN            = 0x01 << 13,   /* Enable error interrupt */
+       INT_ECC_EN              = 0x01 << 14,   /* Enable ECC interrupt */
+
+       INT_FIELD_STATUS        = 0x01 << 16,   /* field interrupt status */
+       INT_VSYNC_STATUS        = 0x01 << 17,   /* vsync interrupt status */
+       INT_HSYNC_STATUS        = 0x01 << 18,   /* hsync interrupt status */
+       INT_VSTART_STATUS       = 0x01 << 19,   /* vstart interrupt status */
+       INT_DMA_END_STATUS      = 0x01 << 20,   /* DMA end interrupt status */
+       INT_ERROR_STATUS        = 0x01 << 21,   /* error interrupt status */
+
+       DMA_ACT                 = 0x01 << 27,   /* Enable DMA transfer */
+       FIELD_NO                = 0x01 << 28,   /* Field number */
+       DITHER_ON               = 0x01 << 29,   /* Dithering is on */
+       ROUND_ON                = 0x01 << 30,   /* Round is on */
+       MODE_32BIT              = 0x01 << 31,   /* Data in RGBa888,
+                                                * 0 in RGB565
+                                                */
+};
+
+#define norm_maxw()    720
+#define norm_maxh()    576
+
+#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \
+                        INT_HSYNC_STATUS | INT_VSTART_STATUS | \
+                        INT_DMA_END_STATUS | INT_ERROR_STATUS)
+
+#define NUM_FORMATS    ARRAY_SIZE(formats)
+
+static irqreturn_t viu_intr(int irq, void *dev_id);
+
+struct viu_fmt *format_by_fourcc(int fourcc)
+{
+       int i;
+
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].pixelformat == fourcc)
+                       return formats + i;
+       }
+
+       dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+       return NULL;
+}
+
+void viu_start_dma(struct viu_dev *dev)
+{
+       struct viu_reg *vr = dev->vr;
+
+       dev->field = 0;
+
+       /* Enable DMA operation */
+       out_be32(&vr->status_cfg, SOFT_RST);
+       out_be32(&vr->status_cfg, INT_FIELD_EN);
+}
+
+void viu_stop_dma(struct viu_dev *dev)
+{
+       struct viu_reg *vr = dev->vr;
+       int cnt = 100;
+       u32 status_cfg;
+
+       out_be32(&vr->status_cfg, 0);
+
+       /* Clear pending interrupts */
+       status_cfg = in_be32(&vr->status_cfg);
+       if (status_cfg & 0x3f0000)
+               out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+
+       if (status_cfg & DMA_ACT) {
+               do {
+                       status_cfg = in_be32(&vr->status_cfg);
+                       if (status_cfg & INT_DMA_END_STATUS)
+                               break;
+               } while (cnt--);
+
+               if (cnt < 0) {
+                       /* timed out, issue soft reset */
+                       out_be32(&vr->status_cfg, SOFT_RST);
+                       out_be32(&vr->status_cfg, 0);
+               } else {
+                       /* clear DMA_END and other pending irqs */
+                       out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+               }
+       }
+
+       dev->field = 0;
+}
+
+static int restart_video_queue(struct viu_dmaqueue *vidq)
+{
+       struct viu_buf *buf, *prev;
+
+       dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
+       if (!list_empty(&vidq->active)) {
+               buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+               dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+                       buf, buf->vb.i);
+
+               viu_stop_dma(vidq->dev);
+
+               /* cancel all outstanding capture requests */
+               list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
+                       list_del(&buf->vb.queue);
+                       buf->vb.state = VIDEOBUF_ERROR;
+                       wake_up(&buf->vb.done);
+               }
+               mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+               return 0;
+       }
+
+       prev = NULL;
+       for (;;) {
+               if (list_empty(&vidq->queued))
+                       return 0;
+               buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
+               if (prev == NULL) {
+                       list_del(&buf->vb.queue);
+                       list_add_tail(&buf->vb.queue, &vidq->active);
+
+                       dprintk(1, "Restarting video dma\n");
+                       viu_stop_dma(vidq->dev);
+                       viu_start_dma(vidq->dev);
+
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+                       dprintk(2, "[%p/%d] restart_queue - first active\n",
+                               buf, buf->vb.i);
+
+               } else if (prev->vb.width  == buf->vb.width  &&
+                          prev->vb.height == buf->vb.height &&
+                          prev->fmt       == buf->fmt) {
+                       list_del(&buf->vb.queue);
+                       list_add_tail(&buf->vb.queue, &vidq->active);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       dprintk(2, "[%p/%d] restart_queue - move to active\n",
+                               buf, buf->vb.i);
+               } else {
+                       return 0;
+               }
+               prev = buf;
+       }
+}
+
+static void viu_vid_timeout(unsigned long data)
+{
+       struct viu_dev *dev = (struct viu_dev *)data;
+       struct viu_buf *buf;
+       struct viu_dmaqueue *vidq = &dev->vidq;
+
+       while (!list_empty(&vidq->active)) {
+               buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+               list_del(&buf->vb.queue);
+               buf->vb.state = VIDEOBUF_ERROR;
+               wake_up(&buf->vb.done);
+               dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
+       }
+
+       restart_video_queue(vidq);
+}
+
+/*
+ * Videobuf operations
+ */
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+                       unsigned int *size)
+{
+       struct viu_fh *fh = vq->priv_data;
+
+       *size = fh->width * fh->height * fh->fmt->depth >> 3;
+       if (*count == 0)
+               *count = 32;
+
+       while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
+               (*count)--;
+
+       dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
+       return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
+{
+       struct videobuf_buffer *vb = &buf->vb;
+       void *vaddr = NULL;
+
+       BUG_ON(in_interrupt());
+
+       videobuf_waiton(&buf->vb, 0, 0);
+
+       if (vq->int_ops && vq->int_ops->vaddr)
+               vaddr = vq->int_ops->vaddr(vb);
+
+       if (vaddr)
+               videobuf_dma_contig_free(vq, &buf->vb);
+
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
+{
+       struct viu_reg *vr = dev->vr;
+       int bpp;
+
+       /* setup the DMA base address */
+       reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
+
+       dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
+               buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
+
+       /* interlace is on by default, set horizontal DMA increment */
+       reg_val.status_cfg = 0;
+       bpp = buf->fmt->depth >> 3;
+       switch (bpp) {
+       case 2:
+               reg_val.status_cfg &= ~MODE_32BIT;
+               reg_val.dma_inc = buf->vb.width * 2;
+               break;
+       case 4:
+               reg_val.status_cfg |= MODE_32BIT;
+               reg_val.dma_inc = buf->vb.width * 4;
+               break;
+       default:
+               dprintk(0, "doesn't support color depth(%d)\n",
+                       bpp * 8);
+               return -EINVAL;
+       }
+
+       /* setup picture_count register */
+       reg_val.picture_count = (buf->vb.height / 2) << 16 |
+                               buf->vb.width;
+
+       reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+       buf->vb.state = VIDEOBUF_ACTIVE;
+       dev->capfield = buf->vb.field;
+
+       /* reset dma increment if needed */
+       if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
+               reg_val.dma_inc = 0;
+
+       out_be32(&vr->dma_inc, reg_val.dma_inc);
+       out_be32(&vr->picture_count, reg_val.picture_count);
+       out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+       mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
+       return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+                         struct videobuf_buffer *vb,
+                         enum v4l2_field field)
+{
+       struct viu_fh  *fh  = vq->priv_data;
+       struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+       int rc;
+
+       BUG_ON(fh->fmt == NULL);
+
+       if (fh->width  < 48 || fh->width  > norm_maxw() ||
+           fh->height < 32 || fh->height > norm_maxh())
+               return -EINVAL;
+       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       if (buf->fmt       != fh->fmt    ||
+           buf->vb.width  != fh->width  ||
+           buf->vb.height != fh->height ||
+           buf->vb.field  != field) {
+               buf->fmt       = fh->fmt;
+               buf->vb.width  = fh->width;
+               buf->vb.height = fh->height;
+               buf->vb.field  = field;
+       }
+
+       if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc != 0)
+                       goto fail;
+
+               buf->vb.width  = fh->width;
+               buf->vb.height = fh->height;
+               buf->vb.field  = field;
+               buf->fmt       = fh->fmt;
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+
+fail:
+       free_buffer(vq, buf);
+       return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct viu_buf       *buf     = container_of(vb, struct viu_buf, vb);
+       struct viu_fh        *fh      = vq->priv_data;
+       struct viu_dev       *dev     = fh->dev;
+       struct viu_dmaqueue  *vidq    = &dev->vidq;
+       struct viu_buf       *prev;
+
+       if (!list_empty(&vidq->queued)) {
+               dprintk(1, "adding vb queue=0x%08lx\n",
+                               (unsigned long)&buf->vb.queue);
+               dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
+                               vidq, &vidq->queued);
+               dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
+                       dev, &vidq->queued, vidq->queued.next,
+                       vidq->queued.prev);
+               list_add_tail(&buf->vb.queue, &vidq->queued);
+               buf->vb.state = VIDEOBUF_QUEUED;
+               dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+                       buf, buf->vb.i);
+       } else if (list_empty(&vidq->active)) {
+               dprintk(1, "adding vb active=0x%08lx\n",
+                               (unsigned long)&buf->vb.queue);
+               list_add_tail(&buf->vb.queue, &vidq->active);
+               buf->vb.state = VIDEOBUF_ACTIVE;
+               mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+               dprintk(2, "[%p/%d] buffer_queue - first active\n",
+                       buf, buf->vb.i);
+
+               buffer_activate(dev, buf);
+       } else {
+               dprintk(1, "adding vb queue2=0x%08lx\n",
+                               (unsigned long)&buf->vb.queue);
+               prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
+               if (prev->vb.width  == buf->vb.width  &&
+                   prev->vb.height == buf->vb.height &&
+                   prev->fmt       == buf->fmt) {
+                       list_add_tail(&buf->vb.queue, &vidq->active);
+                       buf->vb.state = VIDEOBUF_ACTIVE;
+                       dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+                               buf, buf->vb.i);
+               } else {
+                       list_add_tail(&buf->vb.queue, &vidq->queued);
+                       buf->vb.state = VIDEOBUF_QUEUED;
+                       dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+                               buf, buf->vb.i);
+               }
+       }
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+                               struct videobuf_buffer *vb)
+{
+       struct viu_buf *buf  = container_of(vb, struct viu_buf, vb);
+       struct viu_fh  *fh   = vq->priv_data;
+       struct viu_dev *dev  = (struct viu_dev *)fh->dev;
+
+       viu_stop_dma(dev);
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops viu_video_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+};
+
+/*
+ * IOCTL vidioc handling
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "viu");
+       strcpy(cap->card, "viu");
+       cap->version = VIU_VERSION;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_STREAMING     |
+                               V4L2_CAP_VIDEO_OVERLAY |
+                               V4L2_CAP_READWRITE;
+       return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       int index = f->index;
+
+       if (f->index > NUM_FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[index].name, sizeof(f->description));
+       f->pixelformat = formats[index].fourcc;
+       return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct viu_fh *fh = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->vb_vidq.field;
+       f->fmt.pix.pixelformat  = fh->fmt->pixelformat;
+       f->fmt.pix.bytesperline =
+                       (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage    = fh->sizeimage;
+       return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct viu_fmt *fmt;
+       enum v4l2_field field;
+       unsigned int maxw, maxh;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!fmt) {
+               dprintk(1, "Fourcc format (0x%08x) invalid.",
+                       f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       field = f->fmt.pix.field;
+
+       if (field == V4L2_FIELD_ANY) {
+               field = V4L2_FIELD_INTERLACED;
+       } else if (field != V4L2_FIELD_INTERLACED) {
+               dprintk(1, "Field type invalid.\n");
+               return -EINVAL;
+       }
+
+       maxw  = norm_maxw();
+       maxh  = norm_maxh();
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.height < 32)
+               f->fmt.pix.height = 32;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
+       if (f->fmt.pix.width < 48)
+               f->fmt.pix.width = 48;
+       if (f->fmt.pix.width > maxw)
+               f->fmt.pix.width = maxw;
+       f->fmt.pix.width &= ~0x03;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct viu_fh *fh = priv;
+       int ret;
+
+       ret = vidioc_try_fmt_cap(file, fh, f);
+       if (ret < 0)
+               return ret;
+
+       fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->width         = f->fmt.pix.width;
+       fh->height        = f->fmt.pix.height;
+       fh->sizeimage     = f->fmt.pix.sizeimage;
+       fh->vb_vidq.field = f->fmt.pix.field;
+       fh->type          = f->type;
+       dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
+       return 0;
+}
+
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct viu_fh *fh = priv;
+
+       f->fmt.win = fh->win;
+       return 0;
+}
+
+static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
+{
+       enum v4l2_field field;
+       int maxw, maxh;
+
+       if (dev->ovbuf.base == NULL)
+               return -EINVAL;
+       if (dev->ovfmt == NULL)
+               return -EINVAL;
+       if (win->w.width < 48 || win->w.height < 32)
+               return -EINVAL;
+
+       field = win->field;
+       maxw  = dev->crop_current.width;
+       maxh  = dev->crop_current.height;
+
+       if (field == V4L2_FIELD_ANY) {
+               field = (win->w.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
+       }
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       win->field = field;
+       if (win->w.width > maxw)
+               win->w.width = maxw;
+       if (win->w.height > maxh)
+               win->w.height = maxh;
+       return 0;
+}
+
+inline void viu_activate_overlay(struct viu_reg *viu_reg)
+{
+       struct viu_reg *vr = viu_reg;
+
+       out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+       out_be32(&vr->dma_inc, reg_val.dma_inc);
+       out_be32(&vr->picture_count, reg_val.picture_count);
+}
+
+static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+{
+       int bpp;
+
+       dprintk(1, "%s %dx%d %s\n", __func__,
+               fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
+
+       reg_val.status_cfg = 0;
+
+       /* setup window */
+       reg_val.picture_count = (fh->win.w.height / 2) << 16 |
+                               fh->win.w.width;
+
+       /* setup color depth and dma increment */
+       bpp = dev->ovfmt->depth / 8;
+       switch (bpp) {
+       case 2:
+               reg_val.status_cfg &= ~MODE_32BIT;
+               reg_val.dma_inc = fh->win.w.width * 2;
+               break;
+       case 4:
+               reg_val.status_cfg |= MODE_32BIT;
+               reg_val.dma_inc = fh->win.w.width * 4;
+               break;
+       default:
+               dprintk(0, "device doesn't support color depth(%d)\n",
+                       bpp * 8);
+               return -EINVAL;
+       }
+
+       dev->ovfield = fh->win.field;
+       if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
+               reg_val.dma_inc = 0;
+
+       reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+       /* setup the base address of the overlay buffer */
+       reg_val.field_base_addr = (u32)dev->ovbuf.base;
+
+       dev->ovenable = 1;
+       viu_activate_overlay(dev->vr);
+
+       /* start dma */
+       viu_start_dma(dev);
+       return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct viu_fh  *fh  = priv;
+       struct viu_dev *dev = (struct viu_dev *)fh->dev;
+       unsigned long  flags;
+       int err;
+
+       err = verify_preview(dev, &f->fmt.win);
+       if (err)
+               return err;
+
+       mutex_lock(&dev->lock);
+       fh->win = f->fmt.win;
+
+       spin_lock_irqsave(&dev->slock, flags);
+       viu_start_preview(dev, fh);
+       spin_unlock_irqrestore(&dev->slock, flags);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int vidioc_try_fmt_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       return 0;
+}
+
+int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+       struct viu_fh  *fh = priv;
+       struct viu_dev *dev = fh->dev;
+       struct v4l2_framebuffer *fb = arg;
+
+       *fb = dev->ovbuf;
+       fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+       return 0;
+}
+
+int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+       struct viu_fh  *fh = priv;
+       struct viu_dev *dev = fh->dev;
+       struct v4l2_framebuffer *fb = arg;
+       struct viu_fmt *fmt;
+
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       /* check args */
+       fmt = format_by_fourcc(fb->fmt.pixelformat);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       /* ok, accept it */
+       dev->ovbuf = *fb;
+       dev->ovfmt = fmt;
+       if (dev->ovbuf.fmt.bytesperline == 0) {
+               dev->ovbuf.fmt.bytesperline =
+                       dev->ovbuf.fmt.width * fmt->depth / 8;
+       }
+       return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *p)
+{
+       struct viu_fh *fh = priv;
+
+       return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                                       struct v4l2_buffer *p)
+{
+       struct viu_fh *fh = priv;
+
+       return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct viu_fh *fh = priv;
+
+       return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct viu_fh *fh = priv;
+
+       return videobuf_dqbuf(&fh->vb_vidq, p,
+                               file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct viu_fh *fh = priv;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (fh->type != i)
+               return -EINVAL;
+
+       return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct viu_fh  *fh = priv;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (fh->type != i)
+               return -EINVAL;
+
+       return videobuf_streamoff(&fh->vb_vidq);
+}
+
+#define decoder_call(viu, o, f, args...) \
+       v4l2_subdev_call(viu->decoder, o, f, ##args)
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct viu_fh *fh = priv;
+
+       decoder_call(fh->dev, core, s_std, *id);
+       return 0;
+}
+
+/* only one input in this driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *inp)
+{
+       struct viu_fh *fh = priv;
+
+       if (inp->index != 0)
+               return -EINVAL;
+
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = fh->dev->vdev->tvnorms;
+       strcpy(inp->name, "Camera");
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct viu_fh *fh = priv;
+
+       if (i > 1)
+               return -EINVAL;
+
+       decoder_call(fh->dev, video, s_routing, i, 0, 0);
+       return 0;
+}
+
+/* Controls */
+static int vidioc_queryctrl(struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+               if (qc->id && qc->id == viu_qctrl[i].id) {
+                       memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+               if (ctrl->id == viu_qctrl[i].id) {
+                       ctrl->value = qctl_regs[i];
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+               if (ctrl->id == viu_qctrl[i].id) {
+                       if (ctrl->value < viu_qctrl[i].minimum
+                               || ctrl->value > viu_qctrl[i].maximum)
+                                       return -ERANGE;
+                       qctl_regs[i] = ctrl->value;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+inline void viu_activate_next_buf(struct viu_dev *dev,
+                               struct viu_dmaqueue *viuq)
+{
+       struct viu_dmaqueue *vidq = viuq;
+       struct viu_buf *buf;
+
+       /* launch another DMA operation for an active/queued buffer */
+       if (!list_empty(&vidq->active)) {
+               buf = list_entry(vidq->active.next, struct viu_buf,
+                                       vb.queue);
+               dprintk(1, "start another queued buffer: 0x%p\n", buf);
+               buffer_activate(dev, buf);
+       } else if (!list_empty(&vidq->queued)) {
+               buf = list_entry(vidq->queued.next, struct viu_buf,
+                                       vb.queue);
+               list_del(&buf->vb.queue);
+
+               dprintk(1, "start another queued buffer: 0x%p\n", buf);
+               list_add_tail(&buf->vb.queue, &vidq->active);
+               buf->vb.state = VIDEOBUF_ACTIVE;
+               buffer_activate(dev, buf);
+       }
+}
+
+inline void viu_default_settings(struct viu_reg *viu_reg)
+{
+       struct viu_reg *vr = viu_reg;
+
+       out_be32(&vr->luminance, 0x9512A254);
+       out_be32(&vr->chroma_r, 0x03310000);
+       out_be32(&vr->chroma_g, 0x06600F38);
+       out_be32(&vr->chroma_b, 0x00000409);
+       out_be32(&vr->alpha, 0x000000ff);
+       out_be32(&vr->req_alarm, 0x00000090);
+       dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
+               in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
+}
+
+static void viu_overlay_intr(struct viu_dev *dev, u32 status)
+{
+       struct viu_reg *vr = dev->vr;
+
+       if (status & INT_DMA_END_STATUS)
+               dev->dma_done = 1;
+
+       if (status & INT_FIELD_STATUS) {
+               if (dev->dma_done) {
+                       u32 addr = reg_val.field_base_addr;
+
+                       dev->dma_done = 0;
+                       if (status & FIELD_NO)
+                               addr += reg_val.dma_inc;
+
+                       out_be32(&vr->field_base_addr, addr);
+                       out_be32(&vr->dma_inc, reg_val.dma_inc);
+                       out_be32(&vr->status_cfg,
+                                (status & 0xffc0ffff) |
+                                (status & INT_ALL_STATUS) |
+                                reg_val.status_cfg);
+               } else if (status & INT_VSYNC_STATUS) {
+                       out_be32(&vr->status_cfg,
+                                (status & 0xffc0ffff) |
+                                (status & INT_ALL_STATUS) |
+                                reg_val.status_cfg);
+               }
+       }
+}
+
+static void viu_capture_intr(struct viu_dev *dev, u32 status)
+{
+       struct viu_dmaqueue *vidq = &dev->vidq;
+       struct viu_reg *vr = dev->vr;
+       struct viu_buf *buf;
+       int field_num;
+       int need_two;
+       int dma_done = 0;
+
+       field_num = status & FIELD_NO;
+       need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
+
+       if (status & INT_DMA_END_STATUS) {
+               dma_done = 1;
+               if (((field_num == 0) && (dev->field == 0)) ||
+                   (field_num && (dev->field == 1)))
+                       dev->field++;
+       }
+
+       if (status & INT_FIELD_STATUS) {
+               dprintk(1, "irq: field %d, done %d\n",
+                       !!field_num, dma_done);
+               if (unlikely(dev->first)) {
+                       if (field_num == 0) {
+                               dev->first = 0;
+                               dprintk(1, "activate first buf\n");
+                               viu_activate_next_buf(dev, vidq);
+                       } else
+                               dprintk(1, "wait field 0\n");
+                       return;
+               }
+
+               /* setup buffer address for next dma operation */
+               if (!list_empty(&vidq->active)) {
+                       u32 addr = reg_val.field_base_addr;
+
+                       if (field_num && need_two) {
+                               addr += reg_val.dma_inc;
+                               dprintk(1, "field 1, 0x%lx, dev field %d\n",
+                                       (unsigned long)addr, dev->field);
+                       }
+                       out_be32(&vr->field_base_addr, addr);
+                       out_be32(&vr->dma_inc, reg_val.dma_inc);
+                       out_be32(&vr->status_cfg,
+                                (status & 0xffc0ffff) |
+                                (status & INT_ALL_STATUS) |
+                                reg_val.status_cfg);
+                       return;
+               }
+       }
+
+       if (dma_done && field_num && (dev->field == 2)) {
+               dev->field = 0;
+               buf = list_entry(vidq->active.next,
+                                struct viu_buf, vb.queue);
+               dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
+                       buf, buf->vb.i,
+                       (unsigned long)videobuf_to_dma_contig(&buf->vb),
+                       (unsigned long)in_be32(&vr->field_base_addr));
+
+               if (waitqueue_active(&buf->vb.done)) {
+                       list_del(&buf->vb.queue);
+                       do_gettimeofday(&buf->vb.ts);
+                       buf->vb.state = VIDEOBUF_DONE;
+                       buf->vb.field_count++;
+                       wake_up(&buf->vb.done);
+               }
+               /* activate next dma buffer */
+               viu_activate_next_buf(dev, vidq);
+       }
+}
+
+static irqreturn_t viu_intr(int irq, void *dev_id)
+{
+       struct viu_dev *dev  = (struct viu_dev *)dev_id;
+       struct viu_reg *vr = dev->vr;
+       u32 status;
+       u32 error;
+
+       status = in_be32(&vr->status_cfg);
+
+       if (status & INT_ERROR_STATUS) {
+               dev->irqs.error_irq++;
+               error = status & ERR_MASK;
+               if (error)
+                       dprintk(1, "Err: error(%d), times:%d!\n",
+                               error >> 4, dev->irqs.error_irq);
+               /* Clear interrupt error bit and error flags */
+               out_be32(&vr->status_cfg,
+                        (status & 0xffc0ffff) | INT_ERROR_STATUS);
+       }
+
+       if (status & INT_DMA_END_STATUS) {
+               dev->irqs.dma_end_irq++;
+               dev->dma_done = 1;
+               dprintk(2, "VIU DMA end interrupt times: %d\n",
+                                       dev->irqs.dma_end_irq);
+       }
+
+       if (status & INT_HSYNC_STATUS)
+               dev->irqs.hsync_irq++;
+
+       if (status & INT_FIELD_STATUS) {
+               dev->irqs.field_irq++;
+               dprintk(2, "VIU field interrupt times: %d\n",
+                                       dev->irqs.field_irq);
+       }
+
+       if (status & INT_VSTART_STATUS)
+               dev->irqs.vstart_irq++;
+
+       if (status & INT_VSYNC_STATUS) {
+               dev->irqs.vsync_irq++;
+               dprintk(2, "VIU vsync interrupt times: %d\n",
+                       dev->irqs.vsync_irq);
+       }
+
+       /* clear all pending irqs */
+       status = in_be32(&vr->status_cfg);
+       out_be32(&vr->status_cfg,
+                (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
+
+       if (dev->ovenable) {
+               viu_overlay_intr(dev, status);
+               return IRQ_HANDLED;
+       }
+
+       /* Capture mode */
+       viu_capture_intr(dev, status);
+       return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int viu_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct viu_dev *dev = video_get_drvdata(vdev);
+       struct viu_fh *fh;
+       struct viu_reg *vr;
+       int minor = vdev->minor;
+       u32 status_cfg;
+       int i;
+
+       dprintk(1, "viu: open (minor=%d)\n", minor);
+
+       dev->users++;
+       if (dev->users > 1) {
+               dev->users--;
+               return -EBUSY;
+       }
+
+       vr = dev->vr;
+
+       dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+               v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+       /* allocate and initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (!fh) {
+               dev->users--;
+               return -ENOMEM;
+       }
+
+       file->private_data = fh;
+       fh->dev = dev;
+
+       fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_RGB32);
+       fh->width    = norm_maxw();
+       fh->height   = norm_maxh();
+       dev->crop_current.width  = fh->width;
+       dev->crop_current.height = fh->height;
+
+       /* Put all controls at a sane state */
+       for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
+               qctl_regs[i] = viu_qctrl[i].default_value;
+
+       dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+               (unsigned long)fh, (unsigned long)dev,
+               (unsigned long)&dev->vidq);
+       dprintk(1, "Open: list_empty queued=%d\n",
+               list_empty(&dev->vidq.queued));
+       dprintk(1, "Open: list_empty active=%d\n",
+               list_empty(&dev->vidq.active));
+
+       viu_default_settings(vr);
+
+       status_cfg = in_be32(&vr->status_cfg);
+       out_be32(&vr->status_cfg,
+                status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
+                               INT_FIELD_EN | INT_VSTART_EN |
+                               INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
+
+       status_cfg = in_be32(&vr->status_cfg);
+       out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
+
+       spin_lock_init(&fh->vbq_lock);
+       videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
+                                      dev->dev, &fh->vbq_lock,
+                                      fh->type, V4L2_FIELD_INTERLACED,
+                                      sizeof(struct viu_buf), fh);
+       return 0;
+}
+
+static ssize_t viu_read(struct file *file, char __user *data, size_t count,
+                       loff_t *ppos)
+{
+       struct viu_fh *fh = file->private_data;
+       struct viu_dev *dev = fh->dev;
+       int ret = 0;
+
+       dprintk(2, "%s\n", __func__);
+       if (dev->ovenable)
+               dev->ovenable = 0;
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               viu_start_dma(dev);
+               ret = videobuf_read_stream(&fh->vb_vidq, data, count,
+                               ppos, 0, file->f_flags & O_NONBLOCK);
+               return ret;
+       }
+       return 0;
+}
+
+static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct viu_fh *fh = file->private_data;
+       struct videobuf_queue *q = &fh->vb_vidq;
+
+       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+               return POLLERR;
+
+       return videobuf_poll_stream(file, q, wait);
+}
+
+static int viu_release(struct file *file)
+{
+       struct viu_fh *fh = file->private_data;
+       struct viu_dev *dev = fh->dev;
+       int minor = video_devdata(file)->minor;
+
+       viu_stop_dma(dev);
+       videobuf_stop(&fh->vb_vidq);
+
+       kfree(fh);
+
+       dev->users--;
+       dprintk(1, "close (minor=%d, users=%d)\n",
+               minor, dev->users);
+       return 0;
+}
+
+void viu_reset(struct viu_reg *reg)
+{
+       out_be32(&reg->status_cfg, 0);
+       out_be32(&reg->luminance, 0x9512a254);
+       out_be32(&reg->chroma_r, 0x03310000);
+       out_be32(&reg->chroma_g, 0x06600f38);
+       out_be32(&reg->chroma_b, 0x00000409);
+       out_be32(&reg->field_base_addr, 0);
+       out_be32(&reg->dma_inc, 0);
+       out_be32(&reg->picture_count, 0x01e002d0);
+       out_be32(&reg->req_alarm, 0x00000090);
+       out_be32(&reg->alpha, 0x000000ff);
+}
+
+static int viu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct viu_fh *fh = file->private_data;
+       int ret;
+
+       dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+       ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+       dprintk(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,
+               ret);
+
+       return ret;
+}
+
+static struct v4l2_file_operations viu_fops = {
+       .owner          = THIS_MODULE,
+       .open           = viu_open,
+       .release        = viu_release,
+       .read           = viu_read,
+       .poll           = viu_poll,
+       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+       .mmap           = viu_mmap,
+};
+
+static const struct v4l2_ioctl_ops viu_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt,
+       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_cap,
+       .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
+       .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
+       .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
+       .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+       .vidioc_g_fbuf        = vidioc_g_fbuf,
+       .vidioc_s_fbuf        = vidioc_s_fbuf,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+};
+
+static struct video_device viu_template = {
+       .name           = "FSL viu",
+       .fops           = &viu_fops,
+       .minor          = -1,
+       .ioctl_ops      = &viu_ioctl_ops,
+       .release        = video_device_release,
+
+       .tvnorms        = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+       .current_norm   = V4L2_STD_NTSC_M,
+};
+
+static int __devinit viu_of_probe(struct of_device *op,
+                                 const struct of_device_id *match)
+{
+       struct viu_dev *viu_dev;
+       struct video_device *vdev;
+       struct resource r;
+       struct viu_reg __iomem *viu_regs;
+       struct i2c_adapter *ad;
+       int ret, viu_irq;
+
+       ret = of_address_to_resource(op->dev.of_node, 0, &r);
+       if (ret) {
+               dev_err(&op->dev, "Can't parse device node resource\n");
+               return -ENODEV;
+       }
+
+       viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+       if (viu_irq == NO_IRQ) {
+               dev_err(&op->dev, "Error while mapping the irq\n");
+               return -EINVAL;
+       }
+
+       /* request mem region */
+       if (!devm_request_mem_region(&op->dev, r.start,
+                                    sizeof(struct viu_reg), DRV_NAME)) {
+               dev_err(&op->dev, "Error while requesting mem region\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* remap registers */
+       viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
+       if (!viu_regs) {
+               dev_err(&op->dev, "Can't map register set\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* Prepare our private structure */
+       viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+       if (!viu_dev) {
+               dev_err(&op->dev, "Can't allocate private structure\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       viu_dev->vr = viu_regs;
+       viu_dev->irq = viu_irq;
+       viu_dev->dev = &op->dev;
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&viu_dev->vidq.active);
+       INIT_LIST_HEAD(&viu_dev->vidq.queued);
+
+       /* initialize locks */
+       mutex_init(&viu_dev->lock);
+
+       snprintf(viu_dev->v4l2_dev.name,
+                sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
+       ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
+       if (ret < 0) {
+               dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
+               goto err;
+       }
+
+       ad = i2c_get_adapter(0);
+       viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
+                       "saa7115", "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+
+       viu_dev->vidq.timeout.function = viu_vid_timeout;
+       viu_dev->vidq.timeout.data     = (unsigned long)viu_dev;
+       init_timer(&viu_dev->vidq.timeout);
+       viu_dev->first = 1;
+
+       /* Allocate memory for video device */
+       vdev = video_device_alloc();
+       if (vdev == NULL) {
+               ret = -ENOMEM;
+               goto err_vdev;
+       }
+
+       memcpy(vdev, &viu_template, sizeof(viu_template));
+
+       vdev->v4l2_dev = &viu_dev->v4l2_dev;
+
+       viu_dev->vdev = vdev;
+
+       video_set_drvdata(viu_dev->vdev, viu_dev);
+
+       ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret < 0) {
+               video_device_release(viu_dev->vdev);
+               goto err_vdev;
+       }
+
+       /* enable VIU clock */
+       viu_dev->clk = clk_get(&op->dev, "viu_clk");
+       if (IS_ERR(viu_dev->clk)) {
+               dev_err(&op->dev, "failed to find the clock module!\n");
+               ret = -ENODEV;
+               goto err_clk;
+       } else {
+               clk_enable(viu_dev->clk);
+       }
+
+       /* reset VIU module */
+       viu_reset(viu_dev->vr);
+
+       /* install interrupt handler */
+       if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
+               dev_err(&op->dev, "Request VIU IRQ failed.\n");
+               ret = -ENODEV;
+               goto err_irq;
+       }
+
+       dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
+       return ret;
+
+err_irq:
+       clk_disable(viu_dev->clk);
+       clk_put(viu_dev->clk);
+err_clk:
+       video_unregister_device(viu_dev->vdev);
+err_vdev:
+       i2c_put_adapter(ad);
+       v4l2_device_unregister(&viu_dev->v4l2_dev);
+err:
+       irq_dispose_mapping(viu_irq);
+       return ret;
+}
+
+static int __devexit viu_of_remove(struct of_device *op)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+       struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+       struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
+                                             struct v4l2_subdev, list);
+       struct i2c_client *client = v4l2_get_subdevdata(sdev);
+
+       free_irq(dev->irq, (void *)dev);
+       irq_dispose_mapping(dev->irq);
+
+       clk_disable(dev->clk);
+       clk_put(dev->clk);
+
+       video_unregister_device(dev->vdev);
+       i2c_put_adapter(client->adapter);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int viu_suspend(struct of_device *op, pm_message_t state)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+       struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+       clk_disable(dev->clk);
+       return 0;
+}
+
+static int viu_resume(struct of_device *op)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+       struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+       clk_enable(dev->clk);
+       return 0;
+}
+#endif
+
+/*
+ * Initialization and module stuff
+ */
+static struct of_device_id mpc512x_viu_of_match[] = {
+       {
+               .compatible = "fsl,mpc5121-viu",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
+
+static struct of_platform_driver viu_of_platform_driver = {
+       .probe = viu_of_probe,
+       .remove = __devexit_p(viu_of_remove),
+#ifdef CONFIG_PM
+       .suspend = viu_suspend,
+       .resume = viu_resume,
+#endif
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = mpc512x_viu_of_match,
+       },
+};
+
+static int __init viu_init(void)
+{
+       return of_register_platform_driver(&viu_of_platform_driver);
+}
+
+static void __exit viu_exit(void)
+{
+       of_unregister_platform_driver(&viu_of_platform_driver);
+}
+
+module_init(viu_init);
+module_exit(viu_exit);
+
+MODULE_DESCRIPTION("Freescale Video-In(VIU)");
+MODULE_AUTHOR("Hongjun Chen");
+MODULE_LICENSE("GPL");
index 5d920e584de724c4a73e3b366a54f91d376718a3..23db0c29f68c7c91b03a24ec7eb1f02ad59a3786 100644 (file)
@@ -246,6 +246,15 @@ config USB_GSPCA_SPCA561
          To compile this driver as a module, choose M here: the
          module will be called gspca_spca561.
 
+config USB_GSPCA_SPCA1528
+       tristate "SPCA1528 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the SPCA1528 chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_spca1528.
+
 config USB_GSPCA_SQ905
        tristate "SQ Technologies SQ905 based USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
@@ -264,6 +273,15 @@ config USB_GSPCA_SQ905C
          To compile this driver as a module, choose M here: the
          module will be called gspca_sq905c.
 
+config USB_GSPCA_SQ930X
+       tristate "SQ Technologies SQ930X based USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the SQ930X chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_sq930x.
+
 config USB_GSPCA_STK014
        tristate "Syntek DV4000 (STK014) USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index 6e4cf1ce01c9f5044a1500cb01decdc66c87d6f0..f6616db0b7f87cc034908d21fd3266074f1049ab 100644 (file)
@@ -23,8 +23,10 @@ obj-$(CONFIG_USB_GSPCA_SPCA505)  += gspca_spca505.o
 obj-$(CONFIG_USB_GSPCA_SPCA506)  += gspca_spca506.o
 obj-$(CONFIG_USB_GSPCA_SPCA508)  += gspca_spca508.o
 obj-$(CONFIG_USB_GSPCA_SPCA561)  += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o
 obj-$(CONFIG_USB_GSPCA_SQ905)    += gspca_sq905.o
 obj-$(CONFIG_USB_GSPCA_SQ905C)   += gspca_sq905c.o
+obj-$(CONFIG_USB_GSPCA_SQ930X)   += gspca_sq930x.o
 obj-$(CONFIG_USB_GSPCA_SUNPLUS)  += gspca_sunplus.o
 obj-$(CONFIG_USB_GSPCA_STK014)   += gspca_stk014.o
 obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
@@ -58,8 +60,10 @@ gspca_spca505-objs  := spca505.o
 gspca_spca506-objs  := spca506.o
 gspca_spca508-objs  := spca508.o
 gspca_spca561-objs  := spca561.o
+gspca_spca1528-objs := spca1528.o
 gspca_sq905-objs    := sq905.o
 gspca_sq905c-objs   := sq905c.o
+gspca_sq930x-objs   := sq930x.o
 gspca_stk014-objs   := stk014.o
 gspca_stv0680-objs  := stv0680.o
 gspca_sunplus-objs  := sunplus.o
index 19fe6b24c9a34062b8d85c8f56216d323df86ad2..d6a75772f3f80e19c94d7a4cccd2661a14d01347 100644 (file)
@@ -41,7 +41,7 @@ struct sd {
 #define QUALITY_MAX 60
 #define QUALITY_DEF 40
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -845,9 +845,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        /* create the JPEG header */
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (!sd->jpeg_hdr)
-               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -862,11 +859,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /* called on streamoff with alt 0 and on disconnect */
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
        int retry = 50;
 
-       kfree(sd->jpeg_hdr);
-
        if (!gspca_dev->present)
                return;
        reg_w_val(gspca_dev, 0x0000, 0x00);
index 58b696f455be0492c11172ce493a045b0f46d3fb..3747a1dcff5467682bbf8918ec67c7bc0ddf0796 100644 (file)
@@ -1760,22 +1760,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
            data[25] == sd->params.roi.colEnd &&
            data[26] == sd->params.roi.rowStart &&
            data[27] == sd->params.roi.rowEnd) {
-               struct gspca_frame *frame = gspca_get_i_frame(gspca_dev);
+               u8 *image;
 
                atomic_set(&sd->cam_exposure, data[39] * 2);
                atomic_set(&sd->fps, data[41]);
 
-               if (frame == NULL) {
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-                       return;
-               }
-
                /* Check for proper EOF for last frame */
-               if ((frame->data_end - frame->data) > 4 &&
-                   frame->data_end[-4] == 0xff &&
-                   frame->data_end[-3] == 0xff &&
-                   frame->data_end[-2] == 0xff &&
-                   frame->data_end[-1] == 0xff)
+               image = gspca_dev->image;
+               if (image != NULL &&
+                   gspca_dev->image_len > 4 &&
+                   image[gspca_dev->image_len - 4] == 0xff &&
+                   image[gspca_dev->image_len - 3] == 0xff &&
+                   image[gspca_dev->image_len - 2] == 0xff &&
+                   image[gspca_dev->image_len - 1] == 0xff)
                        gspca_frame_add(gspca_dev, LAST_PACKET,
                                                NULL, 0);
 
index 7c31b4f2abea94eaaacc5145fe96dd59c5766cc3..57782e011c9e8ca153002653180c91708000b65a 100644 (file)
@@ -1,6 +1,7 @@
 /* Subdriver for the GL860 chip with the MI2020 sensor
- * Author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
- * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist.
+ * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid
+ * with the help of Kytrix/BUGabundo/Blazercist.
+ * Driver achieved thanks to a webcam gift by Kytrix.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "gl860.h"
 
+static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c};
+
 static u8 dat_bright1[] = {0x8c, 0xa2, 0x06};
 static u8 dat_bright3[] = {0x8c, 0xa1, 0x02};
 static u8 dat_bright4[] = {0x90, 0x00, 0x0f};
 static u8 dat_bright5[] = {0x8c, 0xa1, 0x03};
 static u8 dat_bright6[] = {0x90, 0x00, 0x05};
 
-static u8 dat_dummy1[] = {0x90, 0x00, 0x06};
-/*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/
-/*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/
-
 static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19};
 static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b};
 static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
 static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
 
+static struct idxdata tbl_middle_hvflip_low[] = {
+       {0x33, "\x90\x00\x06"},
+       {6, "\xff\xff\xff"},
+       {0x33, "\x90\x00\x06"},
+       {6, "\xff\xff\xff"},
+       {0x33, "\x90\x00\x06"},
+       {6, "\xff\xff\xff"},
+       {0x33, "\x90\x00\x06"},
+       {6, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_middle_hvflip_big[] = {
+       {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
+       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+       {102, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
+       {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+};
+
+static struct idxdata tbl_end_hvflip[] = {
+       {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+       {6, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+       {6, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+       {6, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+};
+
 static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
 
 static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
 static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
 
-static struct validx tbl_common1[] = {
-       {0x0000, 0x0000},
-       {1, 0xffff}, /* msleep(35); */
-       {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0},
-       {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8},
-       {0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000},
+static struct validx tbl_init_at_startup[] = {
+       {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001,0x00c1},
+       {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+       {53, 0xffff},
+       {0x0040, 0x0000}, {0x0063, 0x0006},
 };
 
-static struct validx tbl_common2[] = {
-       {0x006a, 0x0007},
-       {35, 0xffff},
-       {0x00ef, 0x0006},
-       {35, 0xffff},
-       {0x006a, 0x000d},
-       {35, 0xffff},
-       {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
+static struct validx tbl_common_0B[] = {
+       {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a,0x000d},
+       {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042,0x00c2},
        {0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
 };
 
-static struct idxdata tbl_common3[] = {
-       {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
+static struct idxdata tbl_common_3B[] = {
+       {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
+       {2, "\xff\xff\xff"},
+       {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
        {6, "\xff\xff\xff"}, /* 12 */
        {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
        {2, "\xff\xff\xff"}, /* - */
@@ -98,85 +122,58 @@ static struct idxdata tbl_common3[] = {
        {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
        {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
        {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
-       {1, "\xff\xff\xff"},
        {0x33, "\x78\x00\x00"},
-       {1, "\xff\xff\xff"},
+       {2, "\xff\xff\xff"},
        {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
        {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
        {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
        {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
-       {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"},
-};
-
-static struct idxdata tbl_common4[] = {
-       {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"},
+       {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
+       {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
+       {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
+       {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
+       {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
+       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+       {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
+       {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
+       {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
+       {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
+       {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
+       {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
+       {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
+       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
+       {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
+       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+       {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
+       {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
+       {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
+       {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
+       {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
+       {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
+       {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
+       {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
+       {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
+       {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
+       {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
+       {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
+       {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
+       {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
+       {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
+       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
+       {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
+       {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
+       {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
+       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
+       {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
        {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
        {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
-       {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"},
-       {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"},
-       {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"},
-};
-
-static struct idxdata tbl_common5[] = {
-       {0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"},
-       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"},
-       {0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"},
-       {0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"},
-       {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
-       /* msleep(53); */
-       {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"},
-       {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"},
-       {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
-       {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"},
-       {0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"},
-       {0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"},
-       {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"},
-       {0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"},
-       {0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"},
-       {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
-       {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
-       {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"},
-       {0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"},
-       {0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"},
-       {0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"},
-       {0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"},
-       {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"},
-       {0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"},
-       {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"},
-       {0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"},
-       {0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"},
-       {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"},
-       {0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
-       {0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"},
-       {0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"},
-       {0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"},
-       {0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"},
-       {0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"},
-       {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"},
-       {0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"},
-       {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"},
-       {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"},
-       {0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"},
-       {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"},
-       {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"},
-       {0x33, "\x8c\x24\x15"},
-};
-
-static struct validx tbl_init_at_startup[] = {
-       {0x0000, 0x0000},
-       {53, 0xffff},
-       {0x0010, 0x0010},
-       {53, 0xffff},
-       {0x0008, 0x00c0},
-       {53, 0xffff},
-       {0x0001, 0x00c1},
-       {53, 0xffff},
-       {0x0001, 0x00c2},
-       {53, 0xffff},
-       {0x0020, 0x0006},
-       {53, 0xffff},
-       {0x006a, 0x000d},
-       {53, 0xffff},
+       {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
+       {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
+       {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
+       {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+       {2, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+       {3, "\xff\xff\xff"},
 };
 
 static struct idxdata tbl_init_post_alt_low1[] = {
@@ -209,7 +206,7 @@ static struct idxdata tbl_init_post_alt_low3[] = {
        {2, "\xff\xff\xff"},
        {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
        {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
-       {2, "\xff\xff\xff"}, /* - * */
+       {2, "\xff\xff\xff"},
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
        {2, "\xff\xff\xff"},
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
@@ -217,61 +214,15 @@ static struct idxdata tbl_init_post_alt_low3[] = {
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
        {2, "\xff\xff\xff"},
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
-       {1, "\xff\xff\xff"},
-};
-
-static struct idxdata tbl_init_post_alt_low4[] = {
-       {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
-       {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
-       {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
-       {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
-       {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
-       {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
-       {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
-       {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
-       {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
-       {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
-       {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
-       {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
-       {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
-       {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
-       {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
-       {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
-       {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
-       {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
-       {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
-       {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
-       {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
-       {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
-       {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
-       {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
-       {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
-       {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"},
-       /* Flip/Mirror h/v=1 */
-       {0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
-       {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"},
-       {0x33, "\x90\x00\x06"},
-       {130, "\xff\xff\xff"},
-       {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
-       {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
-       {100, "\xff\xff\xff"},
-       /* ?? */
-       {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"},
-       {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
-       {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
-       /* Brigthness=70 */
-       {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"},
-       {0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
-       /* Sharpness=20 */
-       {0x32, "\x6c\x14\x08"},
 };
 
-static struct idxdata tbl_init_post_alt_big1[] = {
+static struct idxdata tbl_init_post_alt_big[] = {
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
        {2, "\xff\xff\xff"},
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
        {2, "\xff\xff\xff"},
        {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+       {2, "\xff\xff\xff"},
        {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
        {0x33, "\x90\x00\x05"},
        {2, "\xff\xff\xff"},
@@ -285,9 +236,17 @@ static struct idxdata tbl_init_post_alt_big1[] = {
        {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
        {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
        {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+       {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
+       {51, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
+       {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+       {51, "\xff\xff\xff"},
+       {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
+       {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+       {51, "\xff\xff\xff"},
 };
 
-static struct idxdata tbl_init_post_alt_big2[] = {
+static struct idxdata tbl_init_post_alt_3B[] = {
        {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
        {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
        {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
@@ -316,17 +275,6 @@ static struct idxdata tbl_init_post_alt_big2[] = {
        {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
 };
 
-static struct idxdata tbl_init_post_alt_big3[] = {
-       {0x33, "\x8c\xa1\x02"},
-       {0x33, "\x90\x00\x1f"},
-       {0x33, "\x8c\xa1\x02"},
-       {0x33, "\x90\x00\x1f"},
-       {0x33, "\x8c\xa1\x02"},
-       {0x33, "\x90\x00\x1f"},
-       {0x33, "\x8c\xa1\x02"},
-       {0x33, "\x90\x00\x1f"},
-};
-
 static u8 *dat_640  = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
 static u8 *dat_800  = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21";
 static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01";
@@ -351,7 +299,7 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
        sd->vcur.gamma      =  0;
        sd->vcur.hue        =  0;
        sd->vcur.saturation = 60;
-       sd->vcur.whitebal   = 50;
+       sd->vcur.whitebal   =  0; /* 50, not done by hardware */
        sd->vcur.mirror = 0;
        sd->vcur.flip   = 0;
        sd->vcur.AC50Hz = 1;
@@ -361,17 +309,12 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
        sd->vmax.sharpness  =  40;
        sd->vmax.contrast   =   3;
        sd->vmax.gamma      =   2;
-       sd->vmax.hue        =   0 + 1; /* 200 */
-       sd->vmax.saturation =   0;     /* 100 */
-       sd->vmax.whitebal   =   0;     /* 100 */
+       sd->vmax.hue        =   0 + 1; /* 200, not done by hardware */
+       sd->vmax.saturation =   0;     /* 100, not done by hardware */
+       sd->vmax.whitebal   =   2;     /* 100, not done by hardware */
        sd->vmax.mirror = 1;
        sd->vmax.flip   = 1;
        sd->vmax.AC50Hz = 1;
-       if (_MI2020b_) {
-               sd->vmax.contrast  = 0;
-               sd->vmax.gamma     = 0;
-               sd->vmax.backlight = 0;
-       }
 
        sd->dev_camera_settings = mi2020_camera_settings;
        sd->dev_init_at_startup = mi2020_init_at_startup;
@@ -384,51 +327,9 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
 
 static void common(struct gspca_dev *gspca_dev)
 {
-       s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
-
-       if (_MI2020b_) {
-               fetch_validx(gspca_dev, tbl_common1, ARRAY_SIZE(tbl_common1));
-       } else {
-               if (_MI2020_)
-                       ctrl_out(gspca_dev, 0x40,  1, 0x0008, 0x0004,  0, NULL);
-               else
-                       ctrl_out(gspca_dev, 0x40,  1, 0x0002, 0x0004,  0, NULL);
-               msleep(35);
-               fetch_validx(gspca_dev, tbl_common2, ARRAY_SIZE(tbl_common2));
-       }
-       ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0033,  3, "\x86\x25\x01");
-       ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0033,  3, "\x86\x25\x00");
-       msleep(2); /* - * */
-       ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0030,  3, "\x1a\x0a\xcc");
-       if (reso == IMAGE_1600)
-               msleep(2); /* 1600 */
-       fetch_idxdata(gspca_dev, tbl_common3, ARRAY_SIZE(tbl_common3));
-
-       if (_MI2020b_ || _MI2020_)
-               fetch_idxdata(gspca_dev, tbl_common4,
-                               ARRAY_SIZE(tbl_common4));
-
-       fetch_idxdata(gspca_dev, tbl_common5, ARRAY_SIZE(tbl_common5));
-       if (_MI2020b_ || _MI2020_) {
-               /* Different from fret */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78");
-               /* Same as fret */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
-               /* Different from fret */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90");
-       } else {
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80");
-       }
-       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05");
-       msleep(2);
-       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-       if (reso == IMAGE_1600)
-               msleep(14); /* 1600 */
-       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06");
-       msleep(2);
+       fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B));
+       fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B));
+       ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
 }
 
 static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
@@ -441,8 +342,16 @@ static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
        fetch_validx(gspca_dev, tbl_init_at_startup,
                        ARRAY_SIZE(tbl_init_at_startup));
 
+       ctrl_out(gspca_dev, 0x40,  1, 0x7a00, 0x8030,  0, NULL);
+       ctrl_in(gspca_dev, 0xc0,  2, 0x7a00, 0x8030,  1, &c);
+
        common(gspca_dev);
 
+       msleep(61);
+/*     ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000,  0, NULL); */
+/*     msleep(36); */
+       ctrl_out(gspca_dev, 0x40,  1, 0x0001, 0x0000,  0, NULL);
+
        return 0;
 }
 
@@ -450,17 +359,17 @@ static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->mirrorMask = 0;
+       sd->mirrorMask =  0;
+       sd->vold.hue   = -1;
 
-       sd->vold.backlight  = -1;
+       /* These controls need to be reset */
        sd->vold.brightness = -1;
        sd->vold.sharpness  = -1;
-       sd->vold.contrast   = -1;
-       sd->vold.gamma  = -1;
-       sd->vold.hue    = -1;
-       sd->vold.mirror = -1;
-       sd->vold.flip   = -1;
-       sd->vold.AC50Hz = -1;
+
+       /* If not different from default, they do not need to be set */
+       sd->vold.contrast  = 0;
+       sd->vold.gamma     = 0;
+       sd->vold.backlight = 0;
 
        mi2020_init_post_alt(gspca_dev);
 
@@ -472,10 +381,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 
-       s32 backlight = sd->vcur.backlight;
        s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
        s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
        s32 freq   = (sd->vcur.AC50Hz  > 0);
+       s32 wbal   = sd->vcur.whitebal;
 
        u8 dat_freq2[] = {0x90, 0x00, 0x80};
        u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
@@ -484,6 +393,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
        u8 dat_multi4[] = {0x90, 0x00, 0x00};
        u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
        u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+       u8 dat_wbal2[] = {0x90, 0x00, 0x00};
        u8 c;
 
        sd->nbIm = -1;
@@ -491,23 +401,26 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
        dat_freq2[2] = freq ? 0xc0 : 0x80;
        dat_multi1[2] = 0x9d;
        dat_multi3[2] = dat_multi1[2] + 1;
-       dat_multi4[2] = dat_multi2[2] = backlight;
+       if (wbal == 0) {
+               dat_multi4[2] = dat_multi2[2] = 0;
+               dat_wbal2[2] = 0x17;
+       } else if (wbal == 1) {
+               dat_multi4[2] = dat_multi2[2] = 0;
+               dat_wbal2[2] = 0x35;
+       } else if (wbal == 2) {
+               dat_multi4[2] = dat_multi2[2] = 0x20;
+               dat_wbal2[2] = 0x17;
+       }
        dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
        dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
 
        msleep(200);
-
        ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
-       msleep(3); /* 35 * */
+       msleep(2);
 
        common(gspca_dev);
 
-       ctrl_out(gspca_dev, 0x40,  1, 0x0041, 0x0000,  0, NULL);
-       msleep(70);
-
-       if (_MI2020b_)
-               ctrl_out(gspca_dev, 0x40,  1, 0x0040, 0x0000,  0, NULL);
-
+       msleep(142);
        ctrl_out(gspca_dev, 0x40,  1, 0x0010, 0x0010,  0, NULL);
        ctrl_out(gspca_dev, 0x40,  1, 0x0003, 0x00c1,  0, NULL);
        ctrl_out(gspca_dev, 0x40,  1, 0x0042, 0x00c2,  0, NULL);
@@ -523,8 +436,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
                        ctrl_out(gspca_dev, 0x40,  3, 0x0000, 0x0200,
                                12, dat_800);
 
-               if (_MI2020c_)
-                       fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
+               fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
                                        ARRAY_SIZE(tbl_init_post_alt_low1));
 
                if (reso == IMAGE_800)
@@ -534,87 +446,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
                fetch_idxdata(gspca_dev, tbl_init_post_alt_low3,
                                ARRAY_SIZE(tbl_init_post_alt_low3));
 
-               if (_MI2020b_) {
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-                       msleep(150);
-               } else if (_MI2020c_) {
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-                       msleep(120);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-                       msleep(30);
-               } else if (_MI2020_) {
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-                       msleep(120);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-                       msleep(30);
-               }
-
-               /* AC power frequency */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
-               msleep(20);
-               /* backlight */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-               /* at init time but not after */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
-               /* finish the backlight */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
-               msleep(5);/* " */
-
-               if (_MI2020c_) {
-                       fetch_idxdata(gspca_dev, tbl_init_post_alt_low4,
-                                       ARRAY_SIZE(tbl_init_post_alt_low4));
-               } else {
-                       ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
-                       msleep(14); /* 0xd8 */
-
-                       /* flip/mirror */
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_hvflip1);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_hvflip2);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_hvflip3);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_hvflip4);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_hvflip5);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_hvflip6);
-                       msleep(21);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_dummy1);
-                       msleep(5);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_dummy1);
-                       msleep(5);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_dummy1);
-                       msleep(5);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_dummy1);
-                       msleep(5);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_dummy1);
-                       msleep(5);
-                       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-                                       3, dat_dummy1);
-                       /* end of flip/mirror main part */
-                       msleep(246); /* 146 */
-
-                       sd->nbIm = 0;
-               }
+               ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
+               ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+               ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+               msleep(120);
                break;
 
        case IMAGE_1280:
@@ -643,108 +478,62 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
                                        3, "\x90\x04\xb0");
                }
 
-               fetch_idxdata(gspca_dev, tbl_init_post_alt_big1,
-                               ARRAY_SIZE(tbl_init_post_alt_big1));
-
-               if (reso == IMAGE_1600)
-                       msleep(13); /* 1600 */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00");
-               msleep(53);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-               if (reso == IMAGE_1600)
-                       msleep(13); /* 1600 */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-               msleep(53);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
-               if (reso == IMAGE_1600)
-                       msleep(13); /* 1600 */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-               msleep(53);
-
-               if (_MI2020b_) {
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-                       if (reso == IMAGE_1600)
-                               msleep(500); /* 1600 */
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-                       msleep(1850);
-               } else if (_MI2020c_ || _MI2020_) {
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-                       msleep(1850);
-                       ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-                       msleep(30);
-               }
+               fetch_idxdata(gspca_dev, tbl_init_post_alt_big,
+                               ARRAY_SIZE(tbl_init_post_alt_big));
 
-               /* AC power frequency */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
-               msleep(20);
-               /* backlight */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-               /* at init time but not after */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
-               /* finish the backlight */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
-               msleep(6); /* " */
+               ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
+               ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+               ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+               msleep(1850);
+       }
 
-               ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
-               msleep(14);
+       ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
+       msleep(40);
+
+       /* AC power frequency */
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
+       msleep(33);
+       /* light source */
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+       msleep(7);
+       ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
+
+       fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+                       ARRAY_SIZE(tbl_init_post_alt_3B));
+
+       /* hvflip */
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
+       ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
+       msleep(250);
+
+       if (reso == IMAGE_640 || reso == IMAGE_800)
+               fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+                               ARRAY_SIZE(tbl_middle_hvflip_low));
+       else
+               fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+                               ARRAY_SIZE(tbl_middle_hvflip_big));
 
-               if (_MI2020c_)
-                       fetch_idxdata(gspca_dev, tbl_init_post_alt_big2,
-                                       ARRAY_SIZE(tbl_init_post_alt_big2));
+       fetch_idxdata(gspca_dev, tbl_end_hvflip,
+                       ARRAY_SIZE(tbl_end_hvflip));
 
-               /* flip/mirror */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
-               /* end of flip/mirror main part */
-               msleep(16);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-               if (reso == IMAGE_1600)
-                       msleep(25); /* 1600 */
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-               msleep(103);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-               sd->nbIm = 0;
-
-               if (_MI2020c_)
-                       fetch_idxdata(gspca_dev, tbl_init_post_alt_big3,
-                                       ARRAY_SIZE(tbl_init_post_alt_big3));
-       }
+       sd->nbIm = 0;
 
        sd->vold.mirror    = mirror;
        sd->vold.flip      = flip;
        sd->vold.AC50Hz    = freq;
-       sd->vold.backlight = backlight;
+       sd->vold.whitebal  = wbal;
 
        mi2020_camera_settings(gspca_dev);
 
@@ -772,6 +561,7 @@ static int mi2020_configure_alt(struct gspca_dev *gspca_dev)
 static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 
        s32 backlight = sd->vcur.backlight;
        s32 bright =  sd->vcur.brightness;
@@ -782,6 +572,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
        s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
        s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
        s32 freq   = (sd->vcur.AC50Hz > 0);
+       s32 wbal   = sd->vcur.whitebal;
 
        u8 dat_sharp[] = {0x6c, 0x00, 0x08};
        u8 dat_bright2[] = {0x90, 0x00, 0x00};
@@ -792,6 +583,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
        u8 dat_multi4[] = {0x90, 0x00, 0x00};
        u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
        u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+       u8 dat_wbal2[] = {0x90, 0x00, 0x00};
 
        /* Less than 4 images received -> too early to set the settings */
        if (sd->nbIm < 4) {
@@ -809,67 +601,89 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
                msleep(20);
        }
 
+       if (wbal != sd->vold.whitebal) {
+               sd->vold.whitebal = wbal;
+               if (wbal < 0 || wbal > sd->vmax.whitebal)
+                       wbal = 0;
+
+               dat_multi1[2] = 0x9d;
+               dat_multi3[2] = dat_multi1[2] + 1;
+               if (wbal == 0) {
+                       dat_multi4[2] = dat_multi2[2] = 0;
+                       dat_wbal2[2] = 0x17;
+               } else if (wbal == 1) {
+                       dat_multi4[2] = dat_multi2[2] = 0;
+                       dat_wbal2[2] = 0x35;
+               } else if (wbal == 2) {
+                       dat_multi4[2] = dat_multi2[2] = 0x20;
+                       dat_wbal2[2] = 0x17;
+               }
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+       }
+
        if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
                sd->vold.mirror = mirror;
                sd->vold.flip   = flip;
 
                dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
                dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
+
+               fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+                               ARRAY_SIZE(tbl_init_post_alt_3B));
+
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
-               msleep(130);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-               msleep(6);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-               msleep(6);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-               msleep(6);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-               msleep(6);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-               msleep(6);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-               msleep(6);
-
-               /* Sometimes present, sometimes not, useful? */
-               /* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-                * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/
+               msleep(40);
+
+               if (reso == IMAGE_640 || reso == IMAGE_800)
+                       fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+                                       ARRAY_SIZE(tbl_middle_hvflip_low));
+               else
+                       fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+                                       ARRAY_SIZE(tbl_middle_hvflip_big));
+
+               fetch_idxdata(gspca_dev, tbl_end_hvflip,
+                               ARRAY_SIZE(tbl_end_hvflip));
        }
 
-       if (backlight != sd->vold.backlight) {
-               sd->vold.backlight = backlight;
-               if (backlight < 0 || backlight > sd->vmax.backlight)
-                       backlight = 0;
+       if (bright != sd->vold.brightness) {
+               sd->vold.brightness = bright;
+               if (bright < 0 || bright > sd->vmax.brightness)
+                       bright = 0;
 
-               dat_multi1[2] = 0x9d;
-               dat_multi3[2] = dat_multi1[2] + 1;
-               dat_multi4[2] = dat_multi2[2] = backlight;
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+               dat_bright2[2] = bright;
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
+               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
        }
 
-       if (gam != sd->vold.gamma) {
+       if (cntr != sd->vold.contrast || gam != sd->vold.gamma) {
+               sd->vold.contrast = cntr;
+               if (cntr < 0 || cntr > sd->vmax.contrast)
+                       cntr = 0;
                sd->vold.gamma = gam;
                if (gam < 0 || gam > sd->vmax.gamma)
                        gam = 0;
 
                dat_multi1[2] = 0x6d;
                dat_multi3[2] = dat_multi1[2] + 1;
-               dat_multi4[2] = dat_multi2[2] = 0x40 + gam;
+               if (cntr == 0)
+                       cntr = 4;
+               dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam;
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
@@ -878,14 +692,14 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
        }
 
-       if (cntr != sd->vold.contrast) {
-               sd->vold.contrast = cntr;
-               if (cntr < 0 || cntr > sd->vmax.contrast)
-                       cntr = 0;
+       if (backlight != sd->vold.backlight) {
+               sd->vold.backlight = backlight;
+               if (backlight < 0 || backlight > sd->vmax.backlight)
+                       backlight = 0;
 
-               dat_multi1[2] = 0x6d;
+               dat_multi1[2] = 0x9d;
                dat_multi3[2] = dat_multi1[2] + 1;
-               dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr;
+               dat_multi4[2] = dat_multi2[2] = backlight;
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
@@ -894,20 +708,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
                ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
        }
 
-       if (bright != sd->vold.brightness) {
-               sd->vold.brightness = bright;
-               if (bright < 0 || bright > sd->vmax.brightness)
-                       bright = 0;
-
-               dat_bright2[2] = bright;
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
-               ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
-       }
-
        if (sharp != sd->vold.sharpness) {
                sd->vold.sharpness = sharp;
                if (sharp < 0 || sharp > sd->vmax.sharpness)
@@ -928,9 +728,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
 static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev)
 {
        ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
-       msleep(20);
-       if (_MI2020c_ || _MI2020_)
-               ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
-       else
-               ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
+       msleep(40);
+       ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
 }
index d412694c50afc869aaf9b1a618e8d4b1dd3bbf9a..5ae9619d72a5bbaec39524bcf4f3a8344efbe57d 100644 (file)
@@ -69,7 +69,7 @@ static u8 *tbl_640[] = {
        "\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80"
 };
 
-static u8 *tbl_800[] = {
+static u8 *tbl_1280[] = {
        "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
        ,
        "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61"
@@ -217,7 +217,7 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
 
        ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
 
-       tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800;
+       tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280;
 
        ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
                        tbl_length[0], tbl[0]);
index 9e42476c0eafdc55ca04eb0423d4a9f2fb6a9283..e86eb8b4aedc47eb7dbeb24e132a0656e47ebf54 100644 (file)
@@ -63,7 +63,7 @@ static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
 \
        sd->vcur.thename = val;\
        if (gspca_dev->streaming)\
-               sd->dev_camera_settings(gspca_dev);\
+               sd->waitSet = 1;\
        return 0;\
 } \
 static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
@@ -91,7 +91,6 @@ SD_SETGET(contrast)
 /* control table */
 static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
 static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
-static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS];
 static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
 static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
 
@@ -121,8 +120,6 @@ static int gl860_build_control_table(struct gspca_dev *gspca_dev)
                sd_ctrls = sd_ctrls_mi1320;
        else if (_MI2020_)
                sd_ctrls = sd_ctrls_mi2020;
-       else if (_MI2020b_)
-               sd_ctrls = sd_ctrls_mi2020b;
        else if (_OV2640_)
                sd_ctrls = sd_ctrls_ov2640;
        else if (_OV9655_)
@@ -187,19 +184,6 @@ static const struct sd_desc sd_desc_mi2020 = {
        .dq_callback = sd_callback,
 };
 
-static const struct sd_desc sd_desc_mi2020b = {
-       .name        = MODULE_NAME,
-       .ctrls       = sd_ctrls_mi2020b,
-       .nctrls      = GL860_NCTRLS,
-       .config      = sd_config,
-       .init        = sd_init,
-       .isoc_init   = sd_isoc_init,
-       .start       = sd_start,
-       .stop0       = sd_stop0,
-       .pkt_scan    = sd_pkt_scan,
-       .dq_callback = sd_callback,
-};
-
 static const struct sd_desc sd_desc_ov2640 = {
        .name        = MODULE_NAME,
        .ctrls       = sd_ctrls_ov2640,
@@ -235,9 +219,9 @@ static struct v4l2_pix_format mi2020_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0
        },
-       { 800,  600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+       { 800,  598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
                .bytesperline = 800,
-               .sizeimage = 800 * 600,
+               .sizeimage = 800 * 598,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1
        },
@@ -247,9 +231,9 @@ static struct v4l2_pix_format mi2020_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2
        },
-       {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+       {1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
                .bytesperline = 1600,
-               .sizeimage = 1600 * 1200,
+               .sizeimage = 1600 * 1198,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 3
        },
@@ -344,8 +328,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                sd->sensor = ID_OV9655;
        else if (strcmp(sensor, "MI2020") == 0)
                sd->sensor = ID_MI2020;
-       else if (strcmp(sensor, "MI2020b") == 0)
-               sd->sensor = ID_MI2020b;
 
        /* Get sensor and set the suitable init/start/../stop functions */
        if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
@@ -369,13 +351,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                dev_init_settings   = mi2020_init_settings;
                break;
 
-       case ID_MI2020b:
-               gspca_dev->sd_desc = &sd_desc_mi2020b;
-               cam->cam_mode = mi2020_mode;
-               cam->nmodes = ARRAY_SIZE(mi2020_mode);
-               dev_init_settings   = mi2020_init_settings;
-               break;
-
        case ID_OV2640:
                gspca_dev->sd_desc = &sd_desc_ov2640;
                cam->cam_mode = ov2640_mode;
@@ -620,10 +595,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
        else if (len > 1 && r < len)
                PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
 
-       if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index))
-               msleep(1);
-       if (_OV2640_)
-               msleep(1);
+       msleep(1);
 
        return r;
 }
@@ -767,8 +739,6 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
                PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
        } else if (_MI2020_) {
                PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
-       } else if (_MI2020b_) {
-               PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)");
        } else if (_OV9655_) {
                PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
        } else if (_OV2640_) {
index 305061ff8387fb70a31ea88393ec97ff0e0f79af..49ad4acbf602663c0963d09e420aaf8a1cabf149 100644 (file)
 #define ID_OV2640   2
 #define ID_OV9655   4
 #define ID_MI2020   8
-#define ID_MI2020b 16
 
 #define _MI1320_  (((struct sd *) gspca_dev)->sensor == ID_MI1320)
 #define _MI2020_  (((struct sd *) gspca_dev)->sensor == ID_MI2020)
-#define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b)
-#define _MI2020c_ 0
 #define _OV2640_  (((struct sd *) gspca_dev)->sensor == ID_OV2640)
 #define _OV9655_  (((struct sd *) gspca_dev)->sensor == ID_OV9655)
 
 #define IMAGE_640   0
 #define IMAGE_800   1
 #define IMAGE_1280  2
-#define IMAGE_1600 3
+#define IMAGE_1600  3
 
 struct sd_gl860 {
        u16 backlight;
@@ -75,10 +72,10 @@ struct sd {
        int  (*dev_camera_settings)(struct gspca_dev *);
 
        u8   swapRB;
-       u8  mirrorMask;
-       u8  sensor;
-       s32 nbIm;
-       s32 nbRightUp;
+       u8   mirrorMask;
+       u8   sensor;
+       s32  nbIm;
+       s32  nbRightUp;
        u8   waitSet;
 };
 
index 678675bb365256cd289eb31d8095c914163421b7..d951b0f0e05319afa85daf80550a73cd348997a5 100644 (file)
@@ -201,7 +201,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
 
        buffer_len = le16_to_cpu(ep->wMaxPacketSize);
        interval = ep->bInterval;
-       PDEBUG(D_PROBE, "found int in endpoint: 0x%x, "
+       PDEBUG(D_CONF, "found int in endpoint: 0x%x, "
                "buffer_len=%u, interval=%u",
                ep->bEndpointAddress, buffer_len, interval);
 
@@ -226,7 +226,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
        gspca_dev->int_urb = urb;
        ret = usb_submit_urb(urb, GFP_KERNEL);
        if (ret < 0) {
-               PDEBUG(D_ERR, "submit URB failed with error %i", ret);
+               PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
                goto error_submit;
        }
        return ret;
@@ -294,19 +294,6 @@ static inline int gspca_input_connect(struct gspca_dev *dev)
 }
 #endif
 
-/* get the current input frame buffer */
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
-{
-       struct gspca_frame *frame;
-
-       frame = gspca_dev->cur_frame;
-       if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-                               != V4L2_BUF_FLAG_QUEUED)
-               return NULL;
-       return frame;
-}
-EXPORT_SYMBOL(gspca_get_i_frame);
-
 /*
  * fill a video frame from an URB and resubmit
  */
@@ -439,20 +426,20 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
 
        PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
 
-       /* check the availability of the frame buffer */
-       frame = gspca_dev->cur_frame;
-       if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-                                       != V4L2_BUF_FLAG_QUEUED) {
-               gspca_dev->last_packet_type = DISCARD_PACKET;
-               return;
-       }
-
-       /* when start of a new frame, if the current frame buffer
-        * is not queued, discard the whole frame */
        if (packet_type == FIRST_PACKET) {
-               frame->data_end = frame->data;
+               i = atomic_read(&gspca_dev->fr_i);
+
+               /* if there are no queued buffer, discard the whole frame */
+               if (i == atomic_read(&gspca_dev->fr_q)) {
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       return;
+               }
+               j = gspca_dev->fr_queue[i];
+               frame = &gspca_dev->frame[j];
                frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
                frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+               gspca_dev->image = frame->data;
+               gspca_dev->image_len = 0;
        } else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
                if (packet_type == LAST_PACKET)
                        gspca_dev->last_packet_type = packet_type;
@@ -461,34 +448,37 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
 
        /* append the packet to the frame buffer */
        if (len > 0) {
-               if (frame->data_end - frame->data + len
-                                                > frame->v4l2_buf.length) {
-                       PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
-                               frame->data_end - frame->data + len,
-                               frame->v4l2_buf.length);
+               if (gspca_dev->image_len + len > gspca_dev->frsz) {
+                       PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+                               gspca_dev->image_len + len,
+                               gspca_dev->frsz);
                        packet_type = DISCARD_PACKET;
                } else {
-                       memcpy(frame->data_end, data, len);
-                       frame->data_end += len;
+                       memcpy(gspca_dev->image + gspca_dev->image_len,
+                               data, len);
+                       gspca_dev->image_len += len;
                }
        }
        gspca_dev->last_packet_type = packet_type;
 
-       /* if last packet, wake up the application and advance in the queue */
+       /* if last packet, invalidate packet concatenation until
+        * next first packet, wake up the application and advance
+        * in the queue */
        if (packet_type == LAST_PACKET) {
-               frame->v4l2_buf.bytesused = frame->data_end - frame->data;
-               frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-               frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
-               wake_up_interruptible(&gspca_dev->wq);  /* event = new frame */
-               i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
-               gspca_dev->fr_i = i;
-               PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
-                       frame->v4l2_buf.bytesused,
-                       gspca_dev->fr_q,
-                       i,
-                       gspca_dev->fr_o);
+               i = atomic_read(&gspca_dev->fr_i);
                j = gspca_dev->fr_queue[i];
-               gspca_dev->cur_frame = &gspca_dev->frame[j];
+               frame = &gspca_dev->frame[j];
+               frame->v4l2_buf.bytesused = gspca_dev->image_len;
+               frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+                                        | V4L2_BUF_FLAG_DONE)
+                                       & ~V4L2_BUF_FLAG_QUEUED;
+               i = (i + 1) % GSPCA_MAX_FRAMES;
+               atomic_set(&gspca_dev->fr_i, i);
+               wake_up_interruptible(&gspca_dev->wq);  /* event = new frame */
+               PDEBUG(D_FRAM, "frame complete len:%d",
+                       frame->v4l2_buf.bytesused);
+               gspca_dev->image = NULL;
+               gspca_dev->image_len = 0;
        }
 }
 EXPORT_SYMBOL(gspca_frame_add);
@@ -506,36 +496,6 @@ static int gspca_is_compressed(__u32 format)
        return 0;
 }
 
-static void *rvmalloc(long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       mem = vmalloc_32(size);
-       if (mem != NULL) {
-               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, long size)
-{
-       unsigned long adr;
-
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *) adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
 static int frame_alloc(struct gspca_dev *gspca_dev,
                        unsigned int count)
 {
@@ -548,9 +508,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
        PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
        frsz = PAGE_ALIGN(frsz);
        gspca_dev->frsz = frsz;
-       if (count > GSPCA_MAX_FRAMES)
-               count = GSPCA_MAX_FRAMES;
-       gspca_dev->frbuf = rvmalloc(frsz * count);
+       if (count >= GSPCA_MAX_FRAMES)
+               count = GSPCA_MAX_FRAMES - 1;
+       gspca_dev->frbuf = vmalloc_32(frsz * count);
        if (!gspca_dev->frbuf) {
                err("frame alloc failed");
                return -ENOMEM;
@@ -565,14 +525,12 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
                frame->v4l2_buf.length = frsz;
                frame->v4l2_buf.memory = gspca_dev->memory;
                frame->v4l2_buf.sequence = 0;
-               frame->data = frame->data_end =
-                                       gspca_dev->frbuf + i * frsz;
+               frame->data = gspca_dev->frbuf + i * frsz;
                frame->v4l2_buf.m.offset = i * frsz;
        }
-       gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
-       gspca_dev->cur_frame = &gspca_dev->frame[0];
-       gspca_dev->last_packet_type = DISCARD_PACKET;
-       gspca_dev->sequence = 0;
+       atomic_set(&gspca_dev->fr_q, 0);
+       atomic_set(&gspca_dev->fr_i, 0);
+       gspca_dev->fr_o = 0;
        return 0;
 }
 
@@ -582,8 +540,7 @@ static void frame_free(struct gspca_dev *gspca_dev)
 
        PDEBUG(D_STREAM, "frame free");
        if (gspca_dev->frbuf != NULL) {
-               rvfree(gspca_dev->frbuf,
-                       gspca_dev->nframes * gspca_dev->frsz);
+               vfree(gspca_dev->frbuf);
                gspca_dev->frbuf = NULL;
                for (i = 0; i < gspca_dev->nframes; i++)
                        gspca_dev->frame[i].data = NULL;
@@ -683,12 +640,16 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
                                   : USB_ENDPOINT_XFER_ISOC;
        i = gspca_dev->alt;                     /* previous alt setting */
        if (gspca_dev->cam.reverse_alts) {
+               if (gspca_dev->audio)
+                       i++;
                while (++i < gspca_dev->nbalt) {
                        ep = alt_xfer(&intf->altsetting[i], xfer);
                        if (ep)
                                break;
                }
        } else {
+               if (gspca_dev->audio)
+                       i--;
                while (--i >= 0) {
                        ep = alt_xfer(&intf->altsetting[i], xfer);
                        if (ep)
@@ -811,6 +772,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                goto out;
        }
 
+       /* reset the streaming variables */
+       gspca_dev->image = NULL;
+       gspca_dev->image_len = 0;
+       gspca_dev->last_packet_type = DISCARD_PACKET;
+       gspca_dev->sequence = 0;
+
        gspca_dev->usb_err = 0;
 
        /* set the higher alternate setting and
@@ -1433,34 +1400,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        return ret;
 }
 
-/*fixme: have an audio flag in gspca_dev?*/
-static int vidioc_s_audio(struct file *file, void *priv,
-                        struct v4l2_audio *audio)
-{
-       if (audio->index != 0)
-               return -EINVAL;
-       return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                        struct v4l2_audio *audio)
-{
-       strcpy(audio->name, "Microphone");
-       return 0;
-}
-
-static int vidioc_enumaudio(struct file *file, void *priv,
-                        struct v4l2_audio *audio)
-{
-       if (audio->index != 0)
-               return -EINVAL;
-
-       strcpy(audio->name, "Microphone");
-       audio->capability = 0;
-       audio->mode = 0;
-       return 0;
-}
-
 static int vidioc_querymenu(struct file *file, void *priv,
                            struct v4l2_querymenu *qmenu)
 {
@@ -1504,7 +1443,8 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        struct gspca_dev *gspca_dev = priv;
        int i, ret = 0, streaming;
 
-       switch (rb->memory) {
+       i = rb->memory;                 /* (avoid compilation warning) */
+       switch (i) {
        case GSPCA_MEMORY_READ:                 /* (internal call) */
        case V4L2_MEMORY_MMAP:
        case V4L2_MEMORY_USERPTR:
@@ -1626,7 +1566,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
                                enum v4l2_buf_type buf_type)
 {
        struct gspca_dev *gspca_dev = priv;
-       int i, ret;
+       int ret;
 
        if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -1650,12 +1590,10 @@ static int vidioc_streamoff(struct file *file, void *priv,
        gspca_stream_off(gspca_dev);
        mutex_unlock(&gspca_dev->usb_lock);
 
-       /* empty the application queues */
-       for (i = 0; i < gspca_dev->nframes; i++)
-               gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
-       gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
-       gspca_dev->last_packet_type = DISCARD_PACKET;
-       gspca_dev->sequence = 0;
+       /* empty the transfer queues */
+       atomic_set(&gspca_dev->fr_q, 0);
+       atomic_set(&gspca_dev->fr_i, 0);
+       gspca_dev->fr_o = 0;
        ret = 0;
 out:
        mutex_unlock(&gspca_dev->queue_lock);
@@ -1732,7 +1670,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
        int n;
 
        n = parm->parm.capture.readbuffers;
-       if (n == 0 || n > GSPCA_MAX_FRAMES)
+       if (n == 0 || n >= GSPCA_MAX_FRAMES)
                parm->parm.capture.readbuffers = gspca_dev->nbufread;
        else
                gspca_dev->nbufread = n;
@@ -1755,49 +1693,6 @@ static int vidioc_s_parm(struct file *filp, void *priv,
        return 0;
 }
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
-                       struct video_mbuf *mbuf)
-{
-       struct gspca_dev *gspca_dev = file->private_data;
-       int i;
-
-       PDEBUG(D_STREAM, "cgmbuf");
-       if (gspca_dev->nframes == 0) {
-               int ret;
-
-               {
-                       struct v4l2_format fmt;
-
-                       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       i = gspca_dev->cam.nmodes - 1;  /* highest mode */
-                       fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
-                       fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
-                       fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
-                       ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
-                       if (ret != 0)
-                               return ret;
-               }
-               {
-                       struct v4l2_requestbuffers rb;
-
-                       memset(&rb, 0, sizeof rb);
-                       rb.count = 4;
-                       rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       rb.memory = V4L2_MEMORY_MMAP;
-                       ret = vidioc_reqbufs(file, priv, &rb);
-                       if (ret != 0)
-                               return ret;
-               }
-       }
-       mbuf->frames = gspca_dev->nframes;
-       mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
-       for (i = 0; i < mbuf->frames; i++)
-               mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
-       return 0;
-}
-#endif
-
 static int dev_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct gspca_dev *gspca_dev = file->private_data;
@@ -1838,12 +1733,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
                ret = -EINVAL;
                goto out;
        }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       /* v4l1 maps all the buffers */
-       if (i != 0
-           || size != frame->v4l2_buf.length * gspca_dev->nframes)
-#endif
-           if (size != frame->v4l2_buf.length) {
+       if (size != frame->v4l2_buf.length) {
                PDEBUG(D_STREAM, "mmap bad size");
                ret = -EINVAL;
                goto out;
@@ -1883,21 +1773,17 @@ out:
 static int frame_wait(struct gspca_dev *gspca_dev,
                        int nonblock_ing)
 {
-       struct gspca_frame *frame;
-       int i, j, ret;
+       int i, ret;
 
        /* check if a frame is ready */
        i = gspca_dev->fr_o;
-       j = gspca_dev->fr_queue[i];
-       frame = &gspca_dev->frame[j];
-
-       if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) {
+       if (i == atomic_read(&gspca_dev->fr_i)) {
                if (nonblock_ing)
                        return -EAGAIN;
 
                /* wait till a frame is ready */
                ret = wait_event_interruptible_timeout(gspca_dev->wq,
-                       (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) ||
+                       i != atomic_read(&gspca_dev->fr_i) ||
                        !gspca_dev->streaming || !gspca_dev->present,
                        msecs_to_jiffies(3000));
                if (ret < 0)
@@ -1906,11 +1792,7 @@ static int frame_wait(struct gspca_dev *gspca_dev,
                        return -EIO;
        }
 
-       gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
-       PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
-               gspca_dev->fr_q,
-               gspca_dev->fr_i,
-               gspca_dev->fr_o);
+       gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
 
        if (gspca_dev->sd_desc->dq_callback) {
                mutex_lock(&gspca_dev->usb_lock);
@@ -1919,7 +1801,7 @@ static int frame_wait(struct gspca_dev *gspca_dev,
                        gspca_dev->sd_desc->dq_callback(gspca_dev);
                mutex_unlock(&gspca_dev->usb_lock);
        }
-       return j;
+       return gspca_dev->fr_queue[i];
 }
 
 /*
@@ -2024,15 +1906,9 @@ static int vidioc_qbuf(struct file *file, void *priv,
        }
 
        /* put the buffer in the 'queued' queue */
-       i = gspca_dev->fr_q;
+       i = atomic_read(&gspca_dev->fr_q);
        gspca_dev->fr_queue[i] = index;
-       if (gspca_dev->fr_i == i)
-               gspca_dev->cur_frame = frame;
-       gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
-       PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
-               gspca_dev->fr_q,
-               gspca_dev->fr_i,
-               gspca_dev->fr_o);
+       atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES);
 
        v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
        v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
@@ -2088,7 +1964,7 @@ static int read_alloc(struct gspca_dev *gspca_dev,
 static unsigned int dev_poll(struct file *file, poll_table *wait)
 {
        struct gspca_dev *gspca_dev = file->private_data;
-       int i, ret;
+       int ret;
 
        PDEBUG(D_FRAM, "poll");
 
@@ -2106,11 +1982,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
        if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
                return POLLERR;
 
-       /* check the next incoming buffer */
-       i = gspca_dev->fr_o;
-       i = gspca_dev->fr_queue[i];
-       if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
-               ret = POLLIN | POLLRDNORM;      /* something to read */
+       /* check if an image has been received */
+       if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+               ret = POLLIN | POLLRDNORM;      /* yes */
        else
                ret = 0;
        mutex_unlock(&gspca_dev->queue_lock);
@@ -2214,9 +2088,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_queryctrl       = vidioc_queryctrl,
        .vidioc_g_ctrl          = vidioc_g_ctrl,
        .vidioc_s_ctrl          = vidioc_s_ctrl,
-       .vidioc_g_audio         = vidioc_g_audio,
-       .vidioc_s_audio         = vidioc_s_audio,
-       .vidioc_enumaudio       = vidioc_enumaudio,
        .vidioc_querymenu       = vidioc_querymenu,
        .vidioc_enum_input      = vidioc_enum_input,
        .vidioc_g_input         = vidioc_g_input,
@@ -2235,9 +2106,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_s_register      = vidioc_s_register,
 #endif
        .vidioc_g_chip_ident    = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf          = vidiocgmbuf,
-#endif
 };
 
 static struct video_device gspca_template = {
@@ -2253,31 +2121,18 @@ static struct video_device gspca_template = {
  * This function must be called by the sub-driver when it is
  * called for probing a new device.
  */
-int gspca_dev_probe(struct usb_interface *intf,
+int gspca_dev_probe2(struct usb_interface *intf,
                const struct usb_device_id *id,
                const struct sd_desc *sd_desc,
                int dev_size,
                struct module *module)
 {
-       struct usb_interface_descriptor *interface;
        struct gspca_dev *gspca_dev;
        struct usb_device *dev = interface_to_usbdev(intf);
        int ret;
 
        PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
 
-       /* we don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1) {
-               PDEBUG(D_ERR, "Too many config");
-               return -ENODEV;
-       }
-
-       /* the USB video interface must be the first one */
-       interface = &intf->cur_altsetting->desc;
-       if (dev->config->desc.bNumInterfaces != 1 &&
-           interface->bInterfaceNumber != 0)
-               return -ENODEV;
-
        /* create the device */
        if (dev_size < sizeof *gspca_dev)
                dev_size = sizeof *gspca_dev;
@@ -2293,8 +2148,26 @@ int gspca_dev_probe(struct usb_interface *intf,
                goto out;
        }
        gspca_dev->dev = dev;
-       gspca_dev->iface = interface->bInterfaceNumber;
+       gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
        gspca_dev->nbalt = intf->num_altsetting;
+
+       /* check if any audio device */
+       if (dev->config->desc.bNumInterfaces != 1) {
+               int i;
+               struct usb_interface *intf2;
+
+               for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
+                       intf2 = dev->config->interface[i];
+                       if (intf2 != NULL
+                        && intf2->altsetting != NULL
+                        && intf2->altsetting->desc.bInterfaceClass ==
+                                        USB_CLASS_AUDIO) {
+                               gspca_dev->audio = 1;
+                               break;
+                       }
+               }
+       }
+
        gspca_dev->sd_desc = sd_desc;
        gspca_dev->nbufread = 2;
        gspca_dev->empty_packet = -1;   /* don't check the empty packets */
@@ -2345,6 +2218,31 @@ out:
        kfree(gspca_dev);
        return ret;
 }
+EXPORT_SYMBOL(gspca_dev_probe2);
+
+/* same function as the previous one, but check the interface */
+int gspca_dev_probe(struct usb_interface *intf,
+               const struct usb_device_id *id,
+               const struct sd_desc *sd_desc,
+               int dev_size,
+               struct module *module)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+
+       /* we don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1) {
+               PDEBUG(D_ERR, "%04x:%04x too many config",
+                               id->idVendor, id->idProduct);
+               return -ENODEV;
+       }
+
+       /* the USB video interface must be the first one */
+       if (dev->config->desc.bNumInterfaces != 1
+        && intf->cur_altsetting->desc.bInterfaceNumber != 0)
+               return -ENODEV;
+
+       return gspca_dev_probe2(intf, id, sd_desc, dev_size, module);
+}
 EXPORT_SYMBOL(gspca_dev_probe);
 
 /*
index 8b963dfae8610fd857cce31acf1ee0e6649671f0..b749c36d9f7eacf263efbdc222b8fed9603dc672 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
-#include <linux/slab.h>
 
 /* compilation option */
 #define GSPCA_DEBUG 1
@@ -148,7 +147,6 @@ enum gspca_packet_type {
 
 struct gspca_frame {
        __u8 *data;                     /* frame buffer */
-       __u8 *data_end;                 /* end of frame while filling */
        int vma_use_count;
        struct v4l2_buffer v4l2_buf;
 };
@@ -177,13 +175,14 @@ struct gspca_dev {
 
        __u8 *frbuf;                            /* buffer for nframes */
        struct gspca_frame frame[GSPCA_MAX_FRAMES];
-       struct gspca_frame *cur_frame;          /* frame beeing filled */
+       u8 *image;                              /* image beeing filled */
        __u32 frsz;                             /* frame size */
-       char nframes;                           /* number of frames */
-       char fr_i;                              /* frame being filled */
-       char fr_q;                              /* next frame to queue */
-       char fr_o;                              /* next frame to dequeue */
+       u32 image_len;                          /* current length of image */
+       atomic_t fr_q;                          /* next frame to queue */
+       atomic_t fr_i;                          /* frame being filled */
        signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */
+       char nframes;                           /* number of frames */
+       u8 fr_o;                                /* next frame to dequeue */
        __u8 last_packet_type;
        __s8 empty_packet;              /* if (-1) don't check empty packets */
        __u8 streaming;
@@ -199,6 +198,7 @@ struct gspca_dev {
        struct mutex read_lock;         /* read protection */
        struct mutex queue_lock;        /* ISOC queue protection */
        int usb_err;                    /* USB error - protected by usb_lock */
+       u16 pkt_size;                   /* ISOC packet size */
 #ifdef CONFIG_PM
        char frozen;                    /* suspend - resume */
 #endif
@@ -209,7 +209,7 @@ struct gspca_dev {
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
        __u8 nbalt;                     /* number of USB alternate settings */
-       u16 pkt_size;                   /* ISOC packet size */
+       u8 audio;                       /* presence of audio device */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
@@ -217,12 +217,16 @@ int gspca_dev_probe(struct usb_interface *intf,
                const struct sd_desc *sd_desc,
                int dev_size,
                struct module *module);
+int gspca_dev_probe2(struct usb_interface *intf,
+               const struct usb_device_id *id,
+               const struct sd_desc *sd_desc,
+               int dev_size,
+               struct module *module);
 void gspca_disconnect(struct usb_interface *intf);
 void gspca_frame_add(struct gspca_dev *gspca_dev,
                        enum gspca_packet_type packet_type,
                        const u8 *data,
                        int len);
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
 #ifdef CONFIG_PM
 int gspca_suspend(struct usb_interface *intf, pm_message_t message);
 int gspca_resume(struct usb_interface *intf);
index 84ecd56c64709d722988008dba531e929ead1027..12d9cf4caba22ddfdc719d59aa146a7683d5a1fa 100644 (file)
@@ -50,7 +50,7 @@ struct sd {
        struct workqueue_struct *work_thread;
        u8 quality;                              /* image quality */
        u8 jpegqual;                            /* webcam quality */
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
        struct jlj_command {
@@ -282,7 +282,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        destroy_workqueue(dev->work_thread);
        dev->work_thread = NULL;
        mutex_lock(&gspca_dev->usb_lock);
-       kfree(dev->jpeg_hdr);
 }
 
 /* this function is called at probe and resume time */
@@ -298,9 +297,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int ret;
 
        /* create the JPEG header */
-       dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (dev->jpeg_hdr == NULL)
-               return -ENOMEM;
        jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(dev->jpeg_hdr, dev->quality);
index 1127a405c9b2ce2f9687aff3292ecf6fc7d31b6c..51af3ee3ab8550301a3bcb9b00c113a44b323c0a 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef M5602_BRIDGE_H_
 #define M5602_BRIDGE_H_
 
+#include <linux/slab.h>
 #include "gspca.h"
 
 #define MODULE_NAME "ALi m5602"
index 4294c75e3b11d3f23ae361290be87b7d674d9105..b073d66acd04a7ff5c32ad2d407c0ad5da72353a 100644 (file)
@@ -305,30 +305,23 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
                       sd->frame_count);
 
        } else {
-               struct gspca_frame *frame;
                int cur_frame_len;
 
-               frame = gspca_get_i_frame(gspca_dev);
-               if (frame == NULL) {
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-                       return;
-               }
-
-               cur_frame_len = frame->data_end - frame->data;
+               cur_frame_len = gspca_dev->image_len;
                /* Remove urb header */
                data += 4;
                len -= 4;
 
-               if (cur_frame_len + len <= frame->v4l2_buf.length) {
+               if (cur_frame_len + len <= gspca_dev->frsz) {
                        PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
                               sd->frame_count, len);
 
                        gspca_frame_add(gspca_dev, INTER_PACKET,
                                        data, len);
-               } else if (frame->v4l2_buf.length - cur_frame_len > 0) {
+               } else {
                        /* Add the remaining data up to frame size */
                        gspca_frame_add(gspca_dev, INTER_PACKET, data,
-                                   frame->v4l2_buf.length - cur_frame_len);
+                                   gspca_dev->frsz - cur_frame_len);
                }
        }
 }
index 6b3be4fa2c067be5a9045ea0926f040528608692..fbd91545497a8e6b36d36ecae38898664c8e4d34 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/kthread.h>
-#include <linux/slab.h>
 #include "m5602_s5k83a.h"
 
 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
index 3d9229e22b25cf2598f6f326750d66f9309e9695..031f7195ce0dca39f72b60193b83bc7fbafe7cb1 100644 (file)
@@ -41,7 +41,7 @@ struct sd {
 #define QUALITY_MAX 70
 #define QUALITY_DEF 50
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -200,9 +200,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int i;
 
        /* create the JPEG header */
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (!sd->jpeg_hdr)
-               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -317,13 +314,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                PDEBUG(D_ERR, "Camera Stop failed");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
@@ -486,7 +476,6 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
index f36e11a0458d4ca7a248a68d4bc48b46daa5ce90..2b2cbdbf03fe9d005d237d81c5341b0da955a1bb 100644 (file)
 #include <linux/input.h>
 #include "gspca.h"
 
+/* The jpeg_hdr is used by w996Xcf only */
+/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
+#define CONEX_CAM
+#include "jpeg.h"
+
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("OV519 USB Camera Driver");
 MODULE_LICENSE("GPL");
@@ -90,6 +95,7 @@ struct sd {
 #define QUALITY_DEF 50
 
        __u8 stopped;           /* Streaming is temporarily paused */
+       __u8 first_frame;
 
        __u8 frame_rate;        /* current Framerate */
        __u8 clockdiv;          /* clockdiv override */
@@ -115,7 +121,7 @@ struct sd {
        int sensor_height;
        int sensor_reg_cache[256];
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -3147,7 +3153,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->autobrightness = AUTOBRIGHT_DEF;
        if (sd->sensor == SEN_OV7670) {
                sd->freq = OV7670_FREQ_DEF;
-               gspca_dev->ctrl_dis = 1 << FREQ_IDX;
+               gspca_dev->ctrl_dis = (1 << FREQ_IDX) | (1 << COLOR_IDX);
        } else {
                sd->freq = FREQ_DEF;
                gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
@@ -3961,6 +3967,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        sd_reset_snapshot(gspca_dev);
        sd->snapshot_pressed = 0;
 
+       sd->first_frame = 3;
+
        ret = ov51x_restart(sd);
        if (ret < 0)
                goto out;
@@ -4153,13 +4161,23 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
        /* A short read signals EOF */
        if (len < OVFX2_BULK_SIZE) {
-               gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+               /* If the frame is short, and it is one of the first ones
+                  the sensor and bridge are still syncing, so drop it. */
+               if (sd->first_frame) {
+                       sd->first_frame--;
+                       if (gspca_dev->image_len <
+                                 sd->gspca_dev.width * sd->gspca_dev.height)
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+               }
+               gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
                gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
-               return;
        }
-       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
index dc1e4efe30fb9f40f8749215d5a99624e0cb7780..96cb3a97658101aa4d496596e2b2658c20b1c0dc 100644 (file)
@@ -987,13 +987,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        data + 12, len - 12);
                /* If this packet is marked as EOF, end the frame */
                } else if (data[1] & UVC_STREAM_EOF) {
-                       struct gspca_frame *frame;
-
                        sd->last_pts = 0;
-                       frame = gspca_get_i_frame(gspca_dev);
-                       if (frame == NULL)
-                               goto discard;
-                       if (frame->data_end - frame->data + (len - 12) !=
+                       if (gspca_dev->image_len + len - 12 !=
                            gspca_dev->width * gspca_dev->height * 2) {
                                PDEBUG(D_PACK, "wrong sized frame");
                                goto discard;
index 2a68220d1adabff8fc6ae7ccb273016d172f4eb0..a66df07d7625668c485660d807c9dea2549bdee2 100644 (file)
@@ -402,7 +402,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
        memcpy(gspca_dev->usb_buf, buffer, len);
        ret = usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
-                       1,              /* request */
+                       0,              /* request */
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,              /* value */
                        index, gspca_dev->usb_buf, len,
@@ -804,7 +804,6 @@ static const unsigned char pac_jpeg_header2[] = {
 };
 
 static void pac_start_frame(struct gspca_dev *gspca_dev,
-               struct gspca_frame *frame,
                __u16 lines, __u16 samples_per_line)
 {
        unsigned char tmpbuf[4];
@@ -829,19 +828,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct gspca_frame *frame;
+       u8 *image;
        unsigned char *sof;
 
        sof = pac_find_sof(&sd->sof_read, data, len);
        if (sof) {
                int n, lum_offset, footer_length;
 
-               frame = gspca_get_i_frame(gspca_dev);
-               if (frame == NULL) {
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-                       return;
-               }
-
                /* 6 bytes after the FF D9 EOF marker a number of lumination
                   bytes are send corresponding to different parts of the
                   image, the 14th and 15th byte after the EOF seem to
@@ -852,16 +845,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                /* Finish decoding current frame */
                n = (sof - data) - (footer_length + sizeof pac_sof_marker);
                if (n < 0) {
-                       frame->data_end += n;
+                       gspca_dev->image_len += n;
                        n = 0;
+               } else {
+                       gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
                }
-               gspca_frame_add(gspca_dev, INTER_PACKET,
-                                       data, n);
-               if (gspca_dev->last_packet_type != DISCARD_PACKET &&
-                               frame->data_end[-2] == 0xff &&
-                               frame->data_end[-1] == 0xd9)
-                       gspca_frame_add(gspca_dev, LAST_PACKET,
-                                               NULL, 0);
+
+               image = gspca_dev->image;
+               if (image != NULL
+                && image[gspca_dev->image_len - 2] == 0xff
+                && image[gspca_dev->image_len - 1] == 0xd9)
+                       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 
                n = sof - data;
                len -= n;
@@ -877,7 +871,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
                /* Start the new frame with the jpeg header */
                /* The PAC7302 has the image rotated 90 degrees */
-               pac_start_frame(gspca_dev, frame,
+               pac_start_frame(gspca_dev,
                        gspca_dev->width, gspca_dev->height);
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
@@ -1200,6 +1194,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
        {USB_DEVICE(0x093a, 0x2621)},
        {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
        {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
+       {USB_DEVICE(0x093a, 0x2625)},
        {USB_DEVICE(0x093a, 0x2626)},
        {USB_DEVICE(0x093a, 0x2628)},
        {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
index 44fed9686729340777e9425b1ad5e10e56204651..1cb7e99e92bde439fa7d65d3c7d910d7d624180c 100644 (file)
@@ -270,7 +270,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
        memcpy(gspca_dev->usb_buf, buffer, len);
        ret = usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
-                       1,              /* request */
+                       0,              /* request */
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,              /* value */
                        index, gspca_dev->usb_buf, len,
@@ -599,7 +599,6 @@ static const unsigned char pac_jpeg_header2[] = {
 };
 
 static void pac_start_frame(struct gspca_dev *gspca_dev,
-               struct gspca_frame *frame,
                __u16 lines, __u16 samples_per_line)
 {
        unsigned char tmpbuf[4];
@@ -624,19 +623,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 *image;
        unsigned char *sof;
-       struct gspca_frame *frame;
 
        sof = pac_find_sof(&sd->sof_read, data, len);
        if (sof) {
                int n, lum_offset, footer_length;
 
-               frame = gspca_get_i_frame(gspca_dev);
-               if (frame == NULL) {
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-                       return;
-               }
-
                /* 6 bytes after the FF D9 EOF marker a number of lumination
                   bytes are send corresponding to different parts of the
                   image, the 14th and 15th byte after the EOF seem to
@@ -647,16 +640,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                /* Finish decoding current frame */
                n = (sof - data) - (footer_length + sizeof pac_sof_marker);
                if (n < 0) {
-                       frame->data_end += n;
+                       gspca_dev->image_len += n;
                        n = 0;
+               } else {
+                       gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
                }
-               gspca_frame_add(gspca_dev, INTER_PACKET,
-                                       data, n);
-               if (gspca_dev->last_packet_type != DISCARD_PACKET &&
-                               frame->data_end[-2] == 0xff &&
-                               frame->data_end[-1] == 0xd9)
-                       gspca_frame_add(gspca_dev, LAST_PACKET,
-                                               NULL, 0);
+               image = gspca_dev->image;
+               if (image != NULL
+                && image[gspca_dev->image_len - 2] == 0xff
+                && image[gspca_dev->image_len - 1] == 0xd9)
+                       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 
                n = sof - data;
                len -= n;
@@ -671,7 +664,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        atomic_set(&sd->avg_lum, -1);
 
                /* Start the new frame with the jpeg header */
-               pac_start_frame(gspca_dev, frame,
+               pac_start_frame(gspca_dev,
                        gspca_dev->height, gspca_dev->width);
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
index 644a7fd4701ae9961669a74311bbdb8f264bbf8f..83a718f0f3f9841b8412c34967f41476040398e0 100644 (file)
@@ -20,7 +20,6 @@
 
 #ifdef CONFIG_INPUT
 #include <linux/input.h>
-#include <linux/slab.h>
 #endif
 
 #include "gspca.h"
@@ -89,7 +88,7 @@ struct sd {
        u8 hstart;
        u8 vstart;
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
        u8 quality;
 
        u8 flags;
@@ -2162,10 +2161,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int height = gspca_dev->height;
        u8 fmt, scale = 0;
 
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (sd->jpeg_hdr == NULL)
-               return -ENOMEM;
-
        jpeg_define(sd->jpeg_hdr, height, width,
                        0x21);
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -2197,8 +2192,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
        }
 
        configure_sensor_output(gspca_dev, mode);
-       reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
-       reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
+       reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+       reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
        reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
        reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
        reg_w1(gspca_dev, 0x1189, scale);
@@ -2226,12 +2221,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       kfree(sd->jpeg_hdr);
-}
-
 static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2397,7 +2386,6 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
 #ifdef CONFIG_INPUT
        .int_pkt_scan = sd_int_pkt_scan,
index 95354a339e3d3aabd100fd11d26dc893c7e9bee4..204bb3af455999b4733c41383c8db9e61f4c67dc 100644 (file)
@@ -1251,16 +1251,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
                /* In raw mode we sometimes get some garbage after the frame
                   ignore this */
-               struct gspca_frame *frame;
                int used;
                int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
 
-               frame = gspca_get_i_frame(gspca_dev);
-               if (frame == NULL) {
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-                       return;
-               }
-               used = frame->data_end - frame->data;
+               used = gspca_dev->image_len;
                if (used + len > size)
                        len = size - used;
        }
index 176c5b3d5e6f9096df04276a56995d3ce08684e7..ee17b034bf6b9b6b3e77431d236e629afebc5f84 100644 (file)
@@ -22,7 +22,6 @@
 #define MODULE_NAME "sonixj"
 
 #include <linux/input.h>
-#include <linux/slab.h>
 #include "gspca.h"
 #include "jpeg.h"
 
@@ -392,7 +391,7 @@ static const u8 sn_gc0307[0x1c] = {
 
 static const u8 sn_hv7131[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x00,   0x03,   0x64,   0x00,   0x1a,   0x20,   0x20,   0x20,
+       0x00,   0x03,   0x60,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0x81,   0x11,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
@@ -403,7 +402,7 @@ static const u8 sn_hv7131[0x1c] = {
 
 static const u8 sn_mi0360[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x00,   0x61,   0x44,   0x00,   0x1a,   0x20,   0x20,   0x20,
+       0x00,   0x61,   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 */
@@ -1644,6 +1643,7 @@ static void bridge_init(struct gspca_dev *gspca_dev,
                          const u8 *sn9c1xx)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 reg0102[2];
        const u8 *reg9a;
        static const u8 reg9a_def[] =
                {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
@@ -1656,7 +1656,11 @@ static void bridge_init(struct gspca_dev *gspca_dev,
        reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
 
        /* configure gpio */
-       reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
+       reg0102[0] = sn9c1xx[1];
+       reg0102[1] = sn9c1xx[2];
+       if (gspca_dev->audio)
+               reg0102[1] |= 0x04;     /* keep the audio connection */
+       reg_w(gspca_dev, 0x01, reg0102, 2);
        reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
        reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
        switch (sd->sensor) {
@@ -1737,13 +1741,12 @@ static void bridge_init(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x01, 0x40);
                break;
        case SENSOR_PO2030N:
+       case SENSOR_OV7660:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
                reg_w1(gspca_dev, 0x01, 0x62);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
-       case SENSOR_OV7660:
-               /* fall thru */
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
@@ -1816,7 +1819,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        const u8 *sn9c1xx;
-       u8 regGpio[] = { 0x29, 0x74 };
+       u8 regGpio[] = { 0x29, 0x74 };          /* with audio */
        u8 regF1;
 
        /* setup a selector by bridge */
@@ -1856,7 +1859,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        po2030n_probe(gspca_dev);
                        break;
                }
-               regGpio[1] = 0x70;
+               regGpio[1] = 0x70;              /* no audio */
                reg_w(gspca_dev, 0x01, regGpio, 2);
                break;
        default:
@@ -2274,7 +2277,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
-       u8 reg1, reg2, reg17;
+       u8 reg1, reg17;
        const u8 *sn9c1xx;
        const u8 (*init)[8];
        int mode;
@@ -2304,23 +2307,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* initialize the sensor */
        i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
 
-       switch (sd->sensor) {
-       case SENSOR_ADCM1700:
-               reg2 = 0x60;
-               break;
-       case SENSOR_OM6802:
-               reg2 = 0x71;
-               break;
-       case SENSOR_SP80708:
-               reg2 = 0x62;
-               break;
-       default:
-               reg2 = 0x40;
-               break;
-       }
-       reg_w1(gspca_dev, 0x02, reg2);
-       reg_w1(gspca_dev, 0x02, reg2);
-
        reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
        reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
        reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c
new file mode 100644 (file)
index 0000000..3f514eb
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * spca1528 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.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
+ * 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 "spca1528"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("SPCA1528 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       u8 brightness;
+       u8 contrast;
+       u8 hue;
+       u8 color;
+       u8 sharpness;
+
+       u8 pkt_seq;
+
+       u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+/* 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_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolor(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 const struct ctrl sd_ctrls[] = {
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+#define BRIGHTNESS_DEF 128
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 8,
+               .step    = 1,
+#define CONTRAST_DEF 1
+               .default_value = CONTRAST_DEF,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+       {
+           {
+               .id      = V4L2_CID_HUE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Hue",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+#define HUE_DEF 0
+               .default_value = HUE_DEF,
+           },
+           .set = sd_sethue,
+           .get = sd_gethue,
+       },
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Saturation",
+               .minimum = 0,
+               .maximum = 8,
+               .step    = 1,
+#define COLOR_DEF 1
+               .default_value = COLOR_DEF,
+           },
+           .set = sd_setcolor,
+           .get = sd_getcolor,
+       },
+       {
+           {
+               .id      = V4L2_CID_SHARPNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Sharpness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+#define SHARPNESS_DEF 0
+               .default_value = SHARPNESS_DEF,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+/*             (does not work correctly)
+       {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144 * 5 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 3},
+*/
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 4 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+};
+
+/* read <len> bytes to gspca usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+                       u8 req,
+                       u16 index,
+                       int len)
+{
+#if USB_BUF_SZ < 64
+#error "USB buffer too small"
+#endif
+       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),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0x0000,                 /* value */
+                       index,
+                       gspca_dev->usb_buf, len,
+                       500);
+       PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index,
+                        gspca_dev->usb_buf[0]);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_r err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+                       u8 req,
+                       u16 value,
+                       u16 index)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index,
+                       NULL, 0, 500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev,
+                       u8 req,
+                       u16 value,
+                       u16 index,
+                       u8 byte)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte);
+       gspca_dev->usb_buf[0] = byte;
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index,
+                       gspca_dev->usb_buf, 1, 500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void wait_status_0(struct gspca_dev *gspca_dev)
+{
+       int i;
+
+       i = 20;
+       do {
+               reg_r(gspca_dev, 0x21, 0x0000, 1);
+               if (gspca_dev->usb_buf[0] == 0)
+                       return;
+               msleep(30);
+       } while (--i > 0);
+       PDEBUG(D_ERR, "wait_status_0 timeout");
+       gspca_dev->usb_err = -ETIME;
+}
+
+static void wait_status_1(struct gspca_dev *gspca_dev)
+{
+       int i;
+
+       i = 10;
+       do {
+               reg_r(gspca_dev, 0x21, 0x0001, 1);
+               msleep(10);
+               if (gspca_dev->usb_buf[0] == 1) {
+                       reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00);
+                       reg_r(gspca_dev, 0x21, 0x0001, 1);
+                       return;
+               }
+       } while (--i > 0);
+       PDEBUG(D_ERR, "wait_status_1 timeout");
+       gspca_dev->usb_err = -ETIME;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue);
+}
+
+static void setcolor(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness);
+}
+
+/* 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;
+
+       gspca_dev->cam.cam_mode = vga_mode;
+       gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+       gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */
+                       /*fixme: 256 in ms-win traces*/
+
+       sd->brightness = BRIGHTNESS_DEF;
+       sd->contrast = CONTRAST_DEF;
+       sd->hue = HUE_DEF;
+       sd->color = COLOR_DEF;
+       sd->sharpness = SHARPNESS_DEF;
+
+       gspca_dev->nbalt = 4;           /* use alternate setting 3 */
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev, 0x00, 0x0001, 0x2067);
+       reg_w(gspca_dev, 0x00, 0x00d0, 0x206b);
+       reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+       reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+       msleep(8);
+       reg_w(gspca_dev, 0x00, 0x00c0, 0x206b);
+       reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+       reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+
+       reg_r(gspca_dev, 0x20, 0x0000, 1);
+       reg_r(gspca_dev, 0x20, 0x0000, 5);
+       reg_r(gspca_dev, 0x23, 0x0000, 64);
+       PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c],
+                               &gspca_dev->usb_buf[0x30]);
+       reg_r(gspca_dev, 0x23, 0x0001, 64);
+       return gspca_dev->usb_err;
+}
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+       u8 mode;
+
+       reg_r(gspca_dev, 0x00, 0x2520, 1);
+       wait_status_0(gspca_dev);
+       reg_w(gspca_dev, 0xc5, 0x0003, 0x0000);
+       wait_status_1(gspca_dev);
+
+       wait_status_0(gspca_dev);
+       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+       reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode);
+       reg_r(gspca_dev, 0x25, 0x0004, 1);
+       reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);
+       reg_r(gspca_dev, 0x27, 0x0000, 1);
+       return gspca_dev->usb_err;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* initialize the JPEG header */
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x22);          /* JPEG 411 */
+
+       /* the JPEG quality seems to be 82% */
+       jpeg_set_qual(sd->jpeg_hdr, 82);
+
+       /* set the controls */
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+       sethue(gspca_dev);
+       setcolor(gspca_dev);
+       setsharpness(gspca_dev);
+
+       msleep(5);
+       reg_r(gspca_dev, 0x00, 0x2520, 1);
+       msleep(8);
+
+       /* start the capture */
+       wait_status_0(gspca_dev);
+       reg_w(gspca_dev, 0x31, 0x0000, 0x0004);
+       wait_status_1(gspca_dev);
+       wait_status_0(gspca_dev);
+       msleep(200);
+
+       sd->pkt_seq = 0;
+       return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       /* stop the capture */
+       wait_status_0(gspca_dev);
+       reg_w(gspca_dev, 0x31, 0x0000, 0x0000);
+       wait_status_1(gspca_dev);
+       wait_status_0(gspca_dev);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+                       u8 *data,
+                       int len)
+{
+       int i;
+
+       i = 0;
+       do {
+               if (data[i] == 0xff) {
+                       gspca_frame_add(gspca_dev, INTER_PACKET,
+                                       data, i + 1);
+                       len -= i;
+                       data += i;
+                       *data = 0x00;
+                       i = 0;
+               }
+       } while (++i < len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data,                       /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       static const u8 ffd9[] = {0xff, 0xd9};
+
+       /* image packets start with:
+        *      02 8n
+        * with <n> bit:
+        *      0x01: even (0) / odd (1) image
+        *      0x02: end of image when set
+        */
+       if (len < 3)
+               return;                         /* empty packet */
+       if (*data == 0x02) {
+               if (data[1] & 0x02) {
+                       sd->pkt_seq = !(data[1] & 1);
+                       add_packet(gspca_dev, data + 2, len - 2);
+                       gspca_frame_add(gspca_dev, LAST_PACKET,
+                                       ffd9, 2);
+                       return;
+               }
+               if ((data[1] & 1) != sd->pkt_seq)
+                       goto err;
+               if (gspca_dev->last_packet_type == LAST_PACKET)
+                       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                       sd->jpeg_hdr, JPEG_HDR_SZ);
+               add_packet(gspca_dev, data + 2, len - 2);
+               return;
+       }
+err:
+       gspca_dev->last_packet_type = DISCARD_PACKET;
+}
+
+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 gspca_dev->usb_err;
+}
+
+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 gspca_dev->usb_err;
+}
+
+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_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hue = val;
+       if (gspca_dev->streaming)
+               sethue(gspca_dev);
+       return gspca_dev->usb_err;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->hue;
+       return 0;
+}
+
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->color = val;
+       if (gspca_dev->streaming)
+               setcolor(gspca_dev);
+       return gspca_dev->usb_err;
+}
+
+static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->color;
+       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 gspca_dev->usb_err;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
+/* 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,
+       .isoc_init = sd_isoc_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x04fc, 0x1528)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       /* the video interface for isochronous transfer is 1 */
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
+               return -ENODEV;
+
+       return gspca_dev_probe2(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)
+{
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       info("registered");
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index b866c73c97db17d738cf1a6be61f71dbab06e3d3..c02beb6c1e9345e504b9830840e2a0aa37fee873 100644 (file)
@@ -57,7 +57,7 @@ struct sd {
 #define PalmPixDC85 13
 #define ToptroIndus 14
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -669,9 +669,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        __u8 xmult, ymult;
 
        /* create the JPEG header */
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (!sd->jpeg_hdr)
-               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -891,13 +888,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                gspca_dev->usb_buf[0]);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
@@ -1055,7 +1045,6 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
new file mode 100644 (file)
index 0000000..37cee5e
--- /dev/null
@@ -0,0 +1,1402 @@
+/*
+ * SQ930x subdriver
+ *
+ * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
+ * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
+ *
+ * This program is free software; 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 "sq930x"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
+               "Gerard Klaver <gerard at gkall dot hobby dot nl\n"
+               "Sam Revitch <samr7@cs.washington.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define BULK_TRANSFER_LEN 5128
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       u16 expo;
+       u8 gain;
+
+       u8 quality;             /* webcam quality 0..3 */
+#define QUALITY_DEF 1
+
+       u8 gpio[2];
+
+       u8 eof_len;
+       u8 do_ctrl;
+
+       u8 sensor;
+enum {
+       SENSOR_ICX098BQ,
+       SENSOR_LZ24BP,
+       SENSOR_MI0360,
+       SENSOR_MT9V111,
+       SENSOR_OV7660,
+       SENSOR_OV9630,
+} sensors;
+       u8 type;
+#define Generic 0
+#define Creative_live_motion 1
+
+       u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexpo(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 const struct ctrl sd_ctrls[] = {
+       {
+           {
+               .id = V4L2_CID_EXPOSURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Exposure",
+               .minimum = 0x0001,
+               .maximum = 0x0fff,
+               .step = 1,
+#define EXPO_DEF 0x027d
+               .default_value = EXPO_DEF,
+           },
+           .set = sd_setexpo,
+           .get = sd_getexpo,
+       },
+       {
+           {
+               .id = V4L2_CID_GAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gain",
+               .minimum = 0x01,
+               .maximum = 0xff,
+               .step = 1,
+#define GAIN_DEF 0x61
+               .default_value = GAIN_DEF,
+           },
+           .set = sd_setgain,
+           .get = sd_getgain,
+       },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+       {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 5 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 4 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
+};
+
+/* JPEG quality indexed by webcam quality */
+#define QUAL_0 90
+#define QUAL_1 85
+#define QUAL_2 75
+#define QUAL_3 70
+static const u8 quality_tb[4] = { QUAL_0, QUAL_1, QUAL_2, QUAL_3 };
+
+/* sq930x registers */
+#define SQ930_CTRL_UCBUS_IO    0x0001
+#define SQ930_CTRL_I2C_IO      0x0002
+#define SQ930_CTRL_GPIO                0x0005
+#define SQ930_CTRL_CAP_START   0x0010
+#define SQ930_CTRL_CAP_STOP    0x0011
+#define SQ930_CTRL_SET_EXPOSURE 0x001d
+#define SQ930_CTRL_RESET       0x001e
+#define SQ930_CTRL_GET_DEV_INFO 0x001f
+
+/* gpio 1 (8..15) */
+#define SQ930_GPIO_DFL_I2C_SDA 0x0001
+#define SQ930_GPIO_DFL_I2C_SCL 0x0002
+#define SQ930_GPIO_RSTBAR      0x0004
+#define SQ930_GPIO_EXTRA1      0x0040
+#define SQ930_GPIO_EXTRA2      0x0080
+/* gpio 3 (24..31) */
+#define SQ930_GPIO_POWER       0x0200
+#define SQ930_GPIO_DFL_LED     0x1000
+
+struct ucbus_write_cmd {
+       u16     bw_addr;
+       u8      bw_data;
+};
+struct i2c_write_cmd {
+       u8      reg;
+       u16     val;
+};
+
+static const struct ucbus_write_cmd icx098bq_start_0[] = {
+       {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
+       {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
+       {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
+       {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
+       {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
+       {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
+       {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
+       {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
+       {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+       {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+       {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
+       {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+       {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
+       {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+       {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+       {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
+       {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
+       {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
+       {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
+       {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+       {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
+       {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
+       {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
+       {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
+       {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+       {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd icx098bq_start_1[] = {
+       {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xc0},
+       {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xc0},
+       {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+       {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd icx098bq_start_2[] = {
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
+       {0xf807, 0x7f}, {0xf800, 0x03},
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
+       {0xf807, 0x7f}, {0xf800, 0x03},
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
+       {0xf807, 0x7f}, {0xf800, 0x03},
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+       {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_0[] = {
+       {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
+       {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
+       {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
+       {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
+       {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
+       {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
+       {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
+       {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
+       {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+       {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+       {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
+       {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+       {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
+       {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+       {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+       {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
+       {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
+       {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
+       {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
+       {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+       {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
+       {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
+       {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
+       {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
+       {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+       {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
+       {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xb3},
+       {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xb3},
+       {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+       {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
+       {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+       {0xf5f4, 0xc0},
+       {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+       {0xf5f4, 0xc0},
+       {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+       {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_2[] = {
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
+       {0xf807, 0x7f}, {0xf800, 0x03},
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
+       {0xf807, 0x7f}, {0xf800, 0x03},
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
+       {0xf807, 0x7f}, {0xf800, 0x03},
+       {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+       {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd mi0360_start_0[] = {
+       {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
+       {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
+};
+static const struct i2c_write_cmd mi0360_init_23[] = {
+       {0x30, 0x0040},         /* reserved - def 0x0005 */
+       {0x31, 0x0000},         /* reserved - def 0x002a */
+       {0x34, 0x0100},         /* reserved - def 0x0100 */
+       {0x3d, 0x068f},         /* reserved - def 0x068f */
+};
+static const struct i2c_write_cmd mi0360_init_24[] = {
+       {0x03, 0x01e5},         /* window height */
+       {0x04, 0x0285},         /* window width */
+};
+static const struct i2c_write_cmd mi0360_init_25[] = {
+       {0x35, 0x0020},         /* global gain */
+       {0x2b, 0x0020},         /* green1 gain */
+       {0x2c, 0x002a},         /* blue gain */
+       {0x2d, 0x0028},         /* red gain */
+       {0x2e, 0x0020},         /* green2 gain */
+};
+static const struct ucbus_write_cmd mi0360_start_1[] = {
+       {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xa6},
+       {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xa6},
+       {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+       {0xf5f9, 0x00}
+};
+static const struct i2c_write_cmd mi0360_start_2[] = {
+       {0x62, 0x041d},         /* reserved - def 0x0418 */
+};
+static const struct i2c_write_cmd mi0360_start_3[] = {
+       {0x05, 0x007b},         /* horiz blanking */
+};
+static const struct i2c_write_cmd mi0360_start_4[] = {
+       {0x05, 0x03f5},         /* horiz blanking */
+};
+
+static const struct i2c_write_cmd mt9v111_init_0[] = {
+       {0x01, 0x0001},         /* select IFP/SOC registers */
+       {0x06, 0x300c},         /* operating mode control */
+       {0x08, 0xcc00},         /* output format control (RGB) */
+       {0x01, 0x0004},         /* select core registers */
+};
+static const struct i2c_write_cmd mt9v111_init_1[] = {
+       {0x03, 0x01e5},         /* window height */
+       {0x04, 0x0285},         /* window width */
+};
+static const struct i2c_write_cmd mt9v111_init_2[] = {
+       {0x30, 0x7800},
+       {0x31, 0x0000},
+       {0x07, 0x3002},         /* output control */
+       {0x35, 0x0020},         /* global gain */
+       {0x2b, 0x0020},         /* green1 gain */
+       {0x2c, 0x0020},         /* blue gain */
+       {0x2d, 0x0020},         /* red gain */
+       {0x2e, 0x0020},         /* green2 gain */
+};
+static const struct ucbus_write_cmd mt9v111_start_1[] = {
+       {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xaa},
+       {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+       {0xf5f4, 0xaa},
+       {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
+       {0xf5f9, 0x0a}
+};
+static const struct i2c_write_cmd mt9v111_init_3[] = {
+       {0x62, 0x0405},
+};
+static const struct i2c_write_cmd mt9v111_init_4[] = {
+       {0x05, 0x00ce},         /* horizontal blanking */
+};
+
+static const struct ucbus_write_cmd ov7660_start_0[] = {
+       {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
+       {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
+};
+
+static const struct ucbus_write_cmd ov9630_start_0[] = {
+       {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
+       {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
+};
+
+static const struct cap_s {
+       u8      cc_sizeid;
+       u8      cc_bytes[32];
+} capconfig[4][3] = {
+       [SENSOR_ICX098BQ] = {
+               {0,                             /* JPEG, 160x120 */
+                 {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41,
+                  0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+               {2,                             /* JPEG, 320x240 */
+                 {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+                  0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+               {4,                             /* JPEG, 640x480 */
+                 {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+                  0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+       },
+       [SENSOR_LZ24BP] = {
+               {0,                             /* JPEG, 160x120 */
+                 {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41,
+                  0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+               {2,                             /* JPEG, 320x240 */
+                 {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+                  0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+               {4,                             /* JPEG, 640x480 */
+                 {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+                  0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+       },
+       [SENSOR_MI0360] = {
+               {0,                             /* JPEG, 160x120 */
+                 {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b,
+                  0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f,
+                  0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} },
+               {2,                             /* JPEG, 320x240 */
+                 {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+/*fixme                                       03                      e3 */
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+                  0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+               {4,                             /* JPEG, 640x480 */
+                 {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe3,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+                  0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+       },
+       [SENSOR_MT9V111] = {
+               {0,                             /* JPEG, 160x120 */
+                 {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b,
+                  0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f,
+                  0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} },
+               {2,                             /* JPEG, 320x240 */
+                 {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+                  0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+               {4,                             /* JPEG, 640x480 */
+                 {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3,
+                  0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+                  0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+                  0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+       },
+};
+
+struct sensor_s {
+       const char *name;
+       u8 i2c_addr;
+       u8 i2c_dum;
+       u8 gpio[5];
+       u8 cmd_len;
+       const struct ucbus_write_cmd *cmd;
+};
+
+static const struct sensor_s sensor_tb[] = {
+       [SENSOR_ICX098BQ] = {
+               "icx098bp",
+               0x00, 0x00,
+               {0,
+                SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+                SQ930_GPIO_DFL_I2C_SDA,
+                0,
+                SQ930_GPIO_RSTBAR
+               },
+               8, icx098bq_start_0
+           },
+       [SENSOR_LZ24BP] = {
+               "lz24bp",
+               0x00, 0x00,
+               {0,
+                SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+                SQ930_GPIO_DFL_I2C_SDA,
+                0,
+                SQ930_GPIO_RSTBAR
+               },
+               8, lz24bp_start_0
+           },
+       [SENSOR_MI0360] = {
+               "mi0360",
+               0x5d, 0x80,
+               {SQ930_GPIO_RSTBAR,
+                SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+                SQ930_GPIO_DFL_I2C_SDA,
+                0,
+                0
+               },
+               7, mi0360_start_0
+           },
+       [SENSOR_MT9V111] = {
+               "mt9v111",
+               0x5c, 0x7f,
+               {SQ930_GPIO_RSTBAR,
+                SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+                SQ930_GPIO_DFL_I2C_SDA,
+                0,
+                0
+               },
+               7, mi0360_start_0
+           },
+       [SENSOR_OV7660] = {
+               "ov7660",
+               0x21, 0x00,
+               {0,
+                SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+                SQ930_GPIO_DFL_I2C_SDA,
+                0,
+                SQ930_GPIO_RSTBAR
+               },
+               7, ov7660_start_0
+           },
+       [SENSOR_OV9630] = {
+               "ov9630",
+               0x30, 0x00,
+               {0,
+                SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+                SQ930_GPIO_DFL_I2C_SDA,
+                0,
+                SQ930_GPIO_RSTBAR
+               },
+               7, ov9630_start_0
+           },
+};
+
+static void reg_r(struct gspca_dev *gspca_dev,
+               u16 value, int len)
+{
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_rcvctrlpipe(gspca_dev->dev, 0),
+                       0x0c,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, 0, gspca_dev->usb_buf, len,
+                       500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_r %04x failed %d", value, ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x0c,                   /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0,
+                       500);
+       msleep(30);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_w %04x %04x failed %d", value, index, ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
+               const u8 *data, int len)
+{
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
+                       value, index, *data, data[len - 1]);
+       memcpy(gspca_dev->usb_buf, data, len);
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x0c,                   /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, gspca_dev->usb_buf, len,
+                       1000);
+       msleep(30);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_wb %04x %04x failed %d", value, index, ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void i2c_write(struct sd *sd,
+                       const struct i2c_write_cmd *cmd,
+                       int ncmds)
+{
+       struct gspca_dev *gspca_dev = &sd->gspca_dev;
+       const struct sensor_s *sensor;
+       u16 val, idx;
+       u8 *buf;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       sensor = &sensor_tb[sd->sensor];
+
+       val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
+       idx = (cmd->val & 0xff00) | cmd->reg;
+
+       buf = gspca_dev->usb_buf;
+       *buf++ = sensor->i2c_dum;
+       *buf++ = cmd->val;
+
+       while (--ncmds > 0) {
+               cmd++;
+               *buf++ = cmd->reg;
+               *buf++ = cmd->val >> 8;
+               *buf++ = sensor->i2c_dum;
+               *buf++ = cmd->val;
+       }
+
+       PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
+                       val, idx, gspca_dev->usb_buf[0], buf[-1]);
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x0c,                   /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       val, idx,
+                       gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+                       500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "i2c_write failed %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+static void ucbus_write(struct gspca_dev *gspca_dev,
+                       const struct ucbus_write_cmd *cmd,
+                       int ncmds,
+                       int batchsize)
+{
+       u8 *buf;
+       u16 val, idx;
+       int len, ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+#ifdef GSPCA_DEBUG
+       if ((batchsize - 1) * 3 > USB_BUF_SZ) {
+               err("Bug: usb_buf overflow");
+               gspca_dev->usb_err = -ENOMEM;
+               return;
+       }
+#endif
+
+       for (;;) {
+               len = ncmds;
+               if (len > batchsize)
+                       len = batchsize;
+               ncmds -= len;
+
+               val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
+               idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);
+
+               buf = gspca_dev->usb_buf;
+               while (--len > 0) {
+                       cmd++;
+                       *buf++ = cmd->bw_addr;
+                       *buf++ = cmd->bw_addr >> 8;
+                       *buf++ = cmd->bw_data;
+               }
+               if (buf != gspca_dev->usb_buf)
+                       PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
+                                       val, idx,
+                                       gspca_dev->usb_buf[0], buf[-1]);
+               else
+                       PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
+                                       val, idx);
+               ret = usb_control_msg(gspca_dev->dev,
+                               usb_sndctrlpipe(gspca_dev->dev, 0),
+                               0x0c,                   /* request */
+                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               val, idx,
+                               gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+                               500);
+               if (ret < 0) {
+                       PDEBUG(D_ERR, "ucbus_write failed %d", ret);
+                       gspca_dev->usb_err = ret;
+                       return;
+               }
+               msleep(30);
+               if (ncmds <= 0)
+                       break;
+               cmd++;
+       }
+}
+
+static void gpio_set(struct sd *sd, u16 val, u16 mask)
+{
+       struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+       if (mask & 0x00ff) {
+               sd->gpio[0] &= ~mask;
+               sd->gpio[0] |= val;
+               reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
+                       ~sd->gpio[0] << 8);
+       }
+       mask >>= 8;
+       val >>= 8;
+       if (mask) {
+               sd->gpio[1] &= ~mask;
+               sd->gpio[1] |= val;
+               reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
+                       ~sd->gpio[1] << 8);
+       }
+}
+
+static void gpio_init(struct sd *sd,
+                       const u8 *gpio)
+{
+       gpio_set(sd, *gpio++, 0x000f);
+       gpio_set(sd, *gpio++, 0x000f);
+       gpio_set(sd, *gpio++, 0x000f);
+       gpio_set(sd, *gpio++, 0x000f);
+       gpio_set(sd, *gpio, 0x000f);
+}
+
+static void bridge_init(struct sd *sd)
+{
+       static const struct ucbus_write_cmd clkfreq_cmd = {
+                               0xf031, 0       /* SQ930_CLKFREQ_60MHZ */
+       };
+
+       ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);
+
+       gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
+}
+
+static void cmos_probe(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       const struct sensor_s *sensor;
+       static const u8 probe_order[] = {
+/*             SENSOR_LZ24BP,          (tested as ccd) */
+               SENSOR_OV9630,
+               SENSOR_MI0360,
+               SENSOR_OV7660,
+               SENSOR_MT9V111,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
+               sensor = &sensor_tb[probe_order[i]];
+               ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
+               gpio_init(sd, sensor->gpio);
+               msleep(100);
+               reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
+               msleep(100);
+               if (gspca_dev->usb_buf[0] != 0)
+                       break;
+       }
+       if (i >= ARRAY_SIZE(probe_order))
+               PDEBUG(D_PROBE, "Unknown sensor");
+       else
+               sd->sensor = probe_order[i];
+}
+
+static void mt9v111_init(struct gspca_dev *gspca_dev)
+{
+       int i, nwait;
+       static const u8 cmd_001b[] = {
+               0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
+               0x00, 0x00, 0x00
+       };
+       static const u8 cmd_011b[][7] = {
+               {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
+               {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
+               {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
+               {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
+       };
+
+       reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
+       for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
+               reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
+                               ARRAY_SIZE(cmd_011b[0]));
+               msleep(400);
+               nwait = 20;
+               for (;;) {
+                       reg_r(gspca_dev, 0x031b, 1);
+                       if (gspca_dev->usb_buf[0] == 0
+                        || gspca_dev->usb_err != 0)
+                               break;
+                       if (--nwait < 0) {
+                               PDEBUG(D_PROBE, "mt9v111_init timeout");
+                               gspca_dev->usb_err = -ETIME;
+                               return;
+                       }
+                       msleep(50);
+               }
+       }
+}
+
+static void global_init(struct sd *sd, int first_time)
+{
+       switch (sd->sensor) {
+       case SENSOR_ICX098BQ:
+               if (first_time)
+                       ucbus_write(&sd->gspca_dev,
+                                       icx098bq_start_0,
+                                       8, 8);
+               gpio_init(sd, sensor_tb[sd->sensor].gpio);
+               break;
+       case SENSOR_LZ24BP:
+               if (sd->type != Creative_live_motion)
+                       gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
+               else
+                       gpio_set(sd, 0, 0x00ff);
+               msleep(50);
+               if (first_time)
+                       ucbus_write(&sd->gspca_dev,
+                                       lz24bp_start_0,
+                                       8, 8);
+               gpio_init(sd, sensor_tb[sd->sensor].gpio);
+               break;
+       case SENSOR_MI0360:
+               if (first_time)
+                       ucbus_write(&sd->gspca_dev,
+                                       mi0360_start_0,
+                                       ARRAY_SIZE(mi0360_start_0),
+                                       8);
+               gpio_init(sd, sensor_tb[sd->sensor].gpio);
+               gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
+               break;
+       default:
+/*     case SENSOR_MT9V111: */
+               if (first_time)
+                       mt9v111_init(&sd->gspca_dev);
+               else
+                       gpio_init(sd, sensor_tb[sd->sensor].gpio);
+               break;
+       }
+}
+
+static void lz24bp_ppl(struct sd *sd, u16 ppl)
+{
+       struct ucbus_write_cmd cmds[2] = {
+               {0xf810, ppl >> 8},
+               {0xf811, ppl}
+       };
+
+       ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, integclks, intstartclk, frameclks, min_frclk;
+       const struct sensor_s *sensor;
+       u16 cmd;
+       u8 buf[15];
+
+       integclks = sd->expo;
+       i = 0;
+       cmd = SQ930_CTRL_SET_EXPOSURE;
+
+       switch (sd->sensor) {
+       case SENSOR_ICX098BQ:                   /* ccd */
+       case SENSOR_LZ24BP:
+               min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
+               if (integclks >= min_frclk) {
+                       intstartclk = 0;
+                       frameclks = integclks;
+               } else {
+                       intstartclk = min_frclk - integclks;
+                       frameclks = min_frclk;
+               }
+               buf[i++] = intstartclk >> 8;
+               buf[i++] = intstartclk;
+               buf[i++] = frameclks >> 8;
+               buf[i++] = frameclks;
+               buf[i++] = sd->gain;
+               break;
+       default:                                /* cmos */
+/*     case SENSOR_MI0360: */
+/*     case SENSOR_MT9V111: */
+               cmd |= 0x0100;
+               sensor = &sensor_tb[sd->sensor];
+               buf[i++] = sensor->i2c_addr;    /* i2c_slave_addr */
+               buf[i++] = 0x08;        /* 2 * ni2c */
+               buf[i++] = 0x09;        /* reg = shutter width */
+               buf[i++] = integclks >> 8; /* val H */
+               buf[i++] = sensor->i2c_dum;
+               buf[i++] = integclks;   /* val L */
+               buf[i++] = 0x35;        /* reg = global gain */
+               buf[i++] = 0x00;        /* val H */
+               buf[i++] = sensor->i2c_dum;
+               buf[i++] = sd->gain;    /* val L */
+               buf[i++] = 0x00;
+               buf[i++] = 0x00;
+               buf[i++] = 0x00;
+               buf[i++] = 0x00;
+               buf[i++] = 0x83;
+               break;
+       }
+       reg_wb(gspca_dev, cmd, 0, buf, i);
+}
+
+/* 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 sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam = &gspca_dev->cam;
+
+       sd->sensor = id->driver_info >> 8;
+       sd->type = id->driver_info;
+
+       cam->cam_mode = vga_mode;
+       cam->nmodes = ARRAY_SIZE(vga_mode);
+
+       cam->bulk = 1;
+       cam->bulk_size = BULK_TRANSFER_LEN;
+/*     cam->bulk_nurbs = 2;    fixme: if no setexpo sync */
+
+       sd->quality = QUALITY_DEF;
+       sd->gain = GAIN_DEF;
+       sd->expo = EXPO_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;
+
+       sd->gpio[0] = sd->gpio[1] = 0xff;       /* force gpio rewrite */
+
+/*fixme: is this needed for icx098bp and mi0360?
+       if (sd->sensor != SENSOR_LZ24BP)
+               reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
+ */
+
+       reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
+/* it returns:
+ * 03 00 12 93 0b f6 c9 00     live! ultra
+ * 03 00 07 93 0b f6 ca 00     live! ultra for notebook
+ * 03 00 12 93 0b fe c8 00     Trust WB-3500T
+ * 02 00 06 93 0b fe c8 00     Joy-IT 318S
+ * 03 00 12 93 0b f6 cf 00     icam tracer - sensor icx098bq
+ * 02 00 12 93 0b fe cf 00     ProQ Motion Webcam
+ *
+ * byte
+ * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
+ * 1: 00
+ * 2: 06 / 07 / 12 = mode webcam? firmware??
+ * 3: 93 chip = 930b (930b or 930c)
+ * 4: 0b
+ * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
+ * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
+ * 7: 00
+ */
+       PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x",
+                       gspca_dev->usb_buf[0],
+                       gspca_dev->usb_buf[1],
+                       gspca_dev->usb_buf[2],
+                       gspca_dev->usb_buf[3],
+                       gspca_dev->usb_buf[4],
+                       gspca_dev->usb_buf[5],
+                       gspca_dev->usb_buf[6],
+                       gspca_dev->usb_buf[7]);
+
+       bridge_init(sd);
+
+       if (sd->sensor == SENSOR_MI0360) {
+
+               /* no sensor probe for icam tracer */
+               if (gspca_dev->usb_buf[5] == 0xf6) {    /* if CMOS */
+                       sd->sensor = SENSOR_ICX098BQ;
+                       gspca_dev->cam.cam_mode = &vga_mode[1];
+                       gspca_dev->cam.nmodes = 1;      /* only 320x240 */
+               } else {
+                       cmos_probe(gspca_dev);
+               }
+       }
+
+       PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
+
+       global_init(sd, 1);
+       return gspca_dev->usb_err;
+}
+
+/* special function to create the quantization tables of the JPEG header */
+static void sd_jpeg_set_qual(u8 *jpeg_hdr,
+                               int quality)
+{
+       int i, sc1, sc2;
+
+       quality = quality_tb[quality];  /* convert to JPEG quality */
+/*
+ * approximative qualities for Y and U/V:
+ *     quant = 0:94%/91% 1:91%/87% 2:82%/73% 3:69%/56%
+ * should have:
+ *     quant = 0:94%/91% 1:91%/87.5% 2:81.5%/72% 3:69%/54.5%
+ */
+       sc1 = 200 - quality * 2;
+       quality = quality * 7 / 5 - 40;         /* UV quality */
+       sc2 = 200 - quality * 2;
+       for (i = 0; i < 64; i++) {
+               jpeg_hdr[JPEG_QT0_OFFSET + i] =
+                       (jpeg_head[JPEG_QT0_OFFSET + i] * sc1 + 50) / 100;
+               jpeg_hdr[JPEG_QT1_OFFSET + i] =
+                       (jpeg_head[JPEG_QT1_OFFSET + i] * sc2 + 50) / 100;
+       }
+}
+
+/* send the start/stop commands to the webcam */
+static void send_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       const struct cap_s *cap;
+       int mode, quality;
+
+       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+       cap = &capconfig[sd->sensor][mode];
+       quality = sd->quality;
+       reg_wb(gspca_dev, (quality << 12)
+                                | 0x0a00       /* 900 for Bayer */
+                                | SQ930_CTRL_CAP_START,
+                       0x0500                  /* a00 for Bayer */
+                                | cap->cc_sizeid,
+                       cap->cc_bytes, 32);
+};
+static void send_stop(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
+};
+
+/* 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;
+
+       gspca_dev->cam.bulk_nurbs = 1;  /* there must be one URB only */
+       sd->do_ctrl = 0;
+       return 0;
+}
+
+/* start the capture */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int mode;
+
+       /* initialize the JPEG header */
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x21);          /* JPEG 422 */
+       sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+       bridge_init(sd);
+       global_init(sd, 0);
+       msleep(100);
+
+       switch (sd->sensor) {
+       case SENSOR_ICX098BQ:
+               ucbus_write(gspca_dev, icx098bq_start_0,
+                               ARRAY_SIZE(icx098bq_start_0),
+                               8);
+               ucbus_write(gspca_dev, icx098bq_start_1,
+                               ARRAY_SIZE(icx098bq_start_1),
+                               5);
+               ucbus_write(gspca_dev, icx098bq_start_2,
+                               ARRAY_SIZE(icx098bq_start_2),
+                               6);
+               msleep(50);
+
+               /* 1st start */
+               send_start(gspca_dev);
+               gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+               msleep(70);
+               reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+               gpio_set(sd, 0x7f, 0x00ff);
+
+               /* 2nd start */
+               send_start(gspca_dev);
+               gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+               goto out;
+       case SENSOR_LZ24BP:
+               ucbus_write(gspca_dev, lz24bp_start_0,
+                               ARRAY_SIZE(lz24bp_start_0),
+                               8);
+               if (sd->type != Creative_live_motion)
+                       ucbus_write(gspca_dev, lz24bp_start_1_gen,
+                                       ARRAY_SIZE(lz24bp_start_1_gen),
+                                       5);
+               else
+                       ucbus_write(gspca_dev, lz24bp_start_1_clm,
+                                       ARRAY_SIZE(lz24bp_start_1_clm),
+                                       5);
+               ucbus_write(gspca_dev, lz24bp_start_2,
+                               ARRAY_SIZE(lz24bp_start_2),
+                               6);
+               mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+               lz24bp_ppl(sd, mode == 2 ? 0x0564 : 0x0310);
+               msleep(10);
+               break;
+       case SENSOR_MI0360:
+               ucbus_write(gspca_dev, mi0360_start_0,
+                               ARRAY_SIZE(mi0360_start_0),
+                               8);
+               i2c_write(sd, mi0360_init_23,
+                               ARRAY_SIZE(mi0360_init_23));
+               i2c_write(sd, mi0360_init_24,
+                               ARRAY_SIZE(mi0360_init_24));
+               i2c_write(sd, mi0360_init_25,
+                               ARRAY_SIZE(mi0360_init_25));
+               ucbus_write(gspca_dev, mi0360_start_1,
+                               ARRAY_SIZE(mi0360_start_1),
+                               5);
+               i2c_write(sd, mi0360_start_2,
+                               ARRAY_SIZE(mi0360_start_2));
+               i2c_write(sd, mi0360_start_3,
+                               ARRAY_SIZE(mi0360_start_3));
+
+               /* 1st start */
+               send_start(gspca_dev);
+               msleep(60);
+               reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+
+               i2c_write(sd,
+                       mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
+               break;
+       default:
+/*     case SENSOR_MT9V111: */
+               ucbus_write(gspca_dev, mi0360_start_0,
+                               ARRAY_SIZE(mi0360_start_0),
+                               8);
+               i2c_write(sd, mt9v111_init_0,
+                               ARRAY_SIZE(mt9v111_init_0));
+               i2c_write(sd, mt9v111_init_1,
+                               ARRAY_SIZE(mt9v111_init_1));
+               i2c_write(sd, mt9v111_init_2,
+                               ARRAY_SIZE(mt9v111_init_2));
+               ucbus_write(gspca_dev, mt9v111_start_1,
+                               ARRAY_SIZE(mt9v111_start_1),
+                               8);
+               i2c_write(sd, mt9v111_init_3,
+                               ARRAY_SIZE(mt9v111_init_3));
+               i2c_write(sd, mt9v111_init_4,
+                               ARRAY_SIZE(mt9v111_init_4));
+               break;
+       }
+
+       send_start(gspca_dev);
+out:
+       msleep(1000);
+
+       sd->eof_len = 0;        /* init packet scan */
+
+       if (sd->sensor == SENSOR_MT9V111)
+               gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);
+
+       sd->do_ctrl = 1;        /* set the exposure */
+
+       return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_MT9V111)
+               gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
+       send_stop(gspca_dev);
+}
+
+/* function called when the application gets a new frame */
+/* It sets the exposure if required and restart the bulk transfer. */
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int ret;
+
+       if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
+               return;
+       sd->do_ctrl = 0;
+
+       setexposure(gspca_dev);
+
+       gspca_dev->cam.bulk_nurbs = 1;
+       ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
+       if (ret < 0)
+               PDEBUG(D_ERR|D_PACK, "sd_dq_callback() err %d", ret);
+
+       /* wait a little time, otherwise the webcam crashes */
+       msleep(100);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+                       u8 *data,
+                       int len)
+{
+       int i;
+
+       i = 0;
+       do {
+               if (data[i] == 0xff) {
+                       gspca_frame_add(gspca_dev, INTER_PACKET,
+                                       data, i + 1);
+                       len -= i;
+                       data += i;
+                       *data = 0x00;
+                       i = 0;
+               }
+       } while (++i < len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+/* end a frame and start a new one */
+static void eof_sof(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       static const u8 ffd9[] = {0xff, 0xd9};
+
+       /* if control set, stop bulk transfer */
+       if (sd->do_ctrl
+        && gspca_dev->last_packet_type == INTER_PACKET)
+               gspca_dev->cam.bulk_nurbs = 0;
+       gspca_frame_add(gspca_dev, LAST_PACKET,
+                       ffd9, 2);
+       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data,               /* isoc packet */
+                       int len)                /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 *p;
+       int l;
+
+       len -= 8;       /* ignore last 8 bytes (00 00 55 aa 55 aa 00 00) */
+
+       /*
+        * the end/start of frame is indicated by
+        *      0x00 * 16 -  0xab * 8
+        * aligned on 8 bytes boundary
+        */
+       if (sd->eof_len != 0) {         /* if 'abababab' in previous pkt */
+               if (*((u32 *) data) == 0xabababab) {
+                               /*fixme: should remove previous 0000ababab*/
+                       eof_sof(gspca_dev);
+                       data += 4;
+                       len -= 4;
+               }
+               sd->eof_len = 0;
+       }
+       p = data;
+       l = len;
+       for (;;) {
+               if (*((u32 *) p) == 0xabababab) {
+                       if (l < 8) {            /* (may be 4 only) */
+                               sd->eof_len = 1;
+                               break;
+                       }
+                       if (*((u32 *) p + 1) == 0xabababab) {
+                               add_packet(gspca_dev, data, p - data - 16);
+                                               /* remove previous zeros */
+                               eof_sof(gspca_dev);
+                               p += 8;
+                               l -= 8;
+                               if (l <= 0)
+                                       return;
+                               len = l;
+                               data = p;
+                               continue;
+                       }
+               }
+               p += 4;
+               l -= 4;
+               if (l <= 0)
+                       break;
+       }
+       add_packet(gspca_dev, data, len);
+}
+
+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)
+               sd->do_ctrl = 1;
+       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_setexpo(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->expo = val;
+       if (gspca_dev->streaming)
+               sd->do_ctrl = 1;
+       return 0;
+}
+
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->expo;
+       return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int quality;
+
+       if (jcomp->quality >= (QUAL_0 + QUAL_1) / 2)
+               quality = 0;
+       else if (jcomp->quality >= (QUAL_1 + QUAL_2) / 2)
+               quality = 1;
+       else if (jcomp->quality >= (QUAL_2 + QUAL_3) / 2)
+               quality = 2;
+       else
+               quality = 3;
+
+       if (quality != sd->quality) {
+               sd->quality = quality;
+               if (gspca_dev->streaming) {
+                       send_stop(gspca_dev);
+                       sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+                       msleep(70);
+                       send_start(gspca_dev);
+               }
+       }
+       return gspca_dev->usb_err;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = quality_tb[sd->quality];
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
+/* 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,
+       .isoc_init = sd_isoc_init,
+       .start  = sd_start,
+       .stopN  = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+       .dq_callback = sd_dq_callback,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
+};
+
+/* Table of supported USB devices */
+#define ST(sensor, type) \
+       .driver_info = (SENSOR_ ## sensor << 8) \
+                       | (type)
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
+       {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
+       {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
+       {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
+       {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
+       {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
+       {}
+};
+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)
+{
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       info("registered");
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 0fb534210a2c7f4bfe25ba3ca3737df7314feae1..2aedf4b1bfa37504b4b6497d781906243c941a0f 100644 (file)
@@ -36,11 +36,11 @@ struct sd {
        unsigned char colors;
        unsigned char lightfreq;
        u8 quality;
-#define QUALITY_MIN 60
+#define QUALITY_MIN 70
 #define QUALITY_MAX 95
-#define QUALITY_DEF 80
+#define QUALITY_DEF 88
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -337,9 +337,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int ret, value;
 
        /* create the JPEG header */
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (!sd->jpeg_hdr)
-               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -412,13 +409,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        PDEBUG(D_STREAM, "camera stopped");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
@@ -578,7 +568,6 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
        .get_jcomp = sd_get_jcomp,
index 992ce530f138d49265ffce759c5e5036c9400312..053a27e3a40084fb4b4d71bb40d24426d46de0e0 100644 (file)
@@ -30,6 +30,7 @@
 #ifndef STV06XX_H_
 #define STV06XX_H_
 
+#include <linux/slab.h>
 #include "gspca.h"
 
 #define MODULE_NAME "STV06xx"
index 0c786e00ebcf39e758bb60f29f73f82f826fadc4..21d82bab0c2ed34e6fedc972cf1d53724180523e 100644 (file)
@@ -54,7 +54,7 @@ struct sd {
 #define MegapixV4 4
 #define MegaImageVI 5
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -842,9 +842,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int enable;
 
        /* create the JPEG header */
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (!sd->jpeg_hdr)
-               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x22);          /* JPEG 411 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -954,13 +951,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        }
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
@@ -1162,7 +1152,6 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
index 63014372adbc513c485b821fe4b05a08a7befe7a..2a0f12d55e48aab7d6f44c7c2d4a675106d426ff 100644 (file)
@@ -1,5 +1,7 @@
 /*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * T613 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.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
@@ -26,6 +28,7 @@
 
 #define MODULE_NAME "t613"
 
+#include <linux/slab.h>
 #include "gspca.h"
 
 #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
@@ -44,18 +47,20 @@ struct sd {
        u8 gamma;
        u8 sharpness;
        u8 freq;
-       u8 red_balance; /* split balance */
-       u8 blue_balance;
-       u8 global_gain; /* aka gain */
-       u8 whitebalance; /* set default r/g/b and activate */
+       u8 red_gain;
+       u8 blue_gain;
+       u8 green_gain;
+       u8 awb; /* set default r/g/b and activate */
        u8 mirror;
        u8 effect;
 
        u8 sensor;
-#define SENSOR_OM6802 0
-#define SENSOR_OTHER 1
-#define SENSOR_TAS5130A 2
-#define SENSOR_LT168G 3     /* must verify if this is the actual model */
+enum {
+       SENSOR_OM6802,
+       SENSOR_OTHER,
+       SENSOR_TAS5130A,
+       SENSOR_LT168G,          /* must verify if this is the actual model */
+} sensors;
 };
 
 /* V4L2 controls supported by the driver */
@@ -74,24 +79,22 @@ static int sd_getsharpness(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 int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getflip(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_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_gain(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_setmirror(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu);
 
-
 static const struct ctrl sd_ctrls[] = {
        {
         {
@@ -177,8 +180,8 @@ static const struct ctrl sd_ctrls[] = {
 #define MIRROR_DEF 0
          .default_value = MIRROR_DEF,
          },
-        .set = sd_setflip,
-        .get = sd_getflip
+        .set = sd_setmirror,
+        .get = sd_getmirror
        },
        {
         {
@@ -198,15 +201,15 @@ static const struct ctrl sd_ctrls[] = {
         {
          .id =  V4L2_CID_AUTO_WHITE_BALANCE,
          .type = V4L2_CTRL_TYPE_INTEGER,
-         .name = "White Balance",
+         .name = "Auto White Balance",
          .minimum = 0,
          .maximum = 1,
          .step = 1,
-#define WHITE_BALANCE_DEF 0
-         .default_value = WHITE_BALANCE_DEF,
+#define AWB_DEF 0
+         .default_value = AWB_DEF,
          },
-        .set = sd_setwhitebalance,
-        .get = sd_getwhitebalance
+        .set = sd_setawb,
+        .get = sd_getawb
        },
        {
         {
@@ -244,11 +247,11 @@ static const struct ctrl sd_ctrls[] = {
            .minimum = 0x10,
            .maximum = 0x40,
            .step    = 1,
-#define BLUE_BALANCE_DEF 0x20
-           .default_value = BLUE_BALANCE_DEF,
+#define BLUE_GAIN_DEF 0x20
+           .default_value = BLUE_GAIN_DEF,
         },
-       .set = sd_setblue_balance,
-       .get = sd_getblue_balance,
+       .set = sd_setblue_gain,
+       .get = sd_getblue_gain,
        },
        {
         {
@@ -258,11 +261,11 @@ static const struct ctrl sd_ctrls[] = {
            .minimum = 0x10,
            .maximum = 0x40,
            .step    = 1,
-#define RED_BALANCE_DEF 0x20
-           .default_value = RED_BALANCE_DEF,
+#define RED_GAIN_DEF 0x20
+           .default_value = RED_GAIN_DEF,
         },
-       .set = sd_setred_balance,
-       .get = sd_getred_balance,
+       .set = sd_setred_gain,
+       .get = sd_getred_gain,
        },
        {
         {
@@ -272,24 +275,14 @@ static const struct ctrl sd_ctrls[] = {
            .minimum = 0x10,
            .maximum = 0x40,
            .step    = 1,
-#define global_gain_DEF  0x20
-           .default_value = global_gain_DEF,
+#define GAIN_DEF  0x20
+           .default_value = GAIN_DEF,
         },
-       .set = sd_setglobal_gain,
-       .get = sd_getglobal_gain,
+       .set = sd_setgain,
+       .get = sd_getgain,
        },
 };
 
-static char *effects_control[] = {
-       "Normal",
-       "Emboss",               /* disabled */
-       "Monochrome",
-       "Sepia",
-       "Sketch",
-       "Sun Effect",           /* disabled */
-       "Negative",
-};
-
 static const struct v4l2_pix_format vga_mode_t16[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 160,
@@ -327,7 +320,6 @@ struct additional_sensor_data {
        const u8 data1[10];
        const u8 data2[9];
        const u8 data3[9];
-       const u8 data4[4];
        const u8 data5[6];
        const u8 stream[4];
 };
@@ -375,7 +367,7 @@ static const u8 n4_lt168g[] = {
 };
 
 static const struct additional_sensor_data sensor_data[] = {
-    {                          /* 0: OM6802 */
+[SENSOR_OM6802] = {
        .n3 =
                {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
        .n4 = n4_om6802,
@@ -392,14 +384,12 @@ static const struct additional_sensor_data sensor_data[] = {
        .data3 =
                {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
                 0xff},
-       .data4 =        /*Freq (50/60Hz). Splitted for test purpose */
-               {0x66, 0xca, 0xa8, 0xf0},
        .data5 =        /* this could be removed later */
                {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
        .stream =
                {0x0b, 0x04, 0x0a, 0x78},
     },
-    {                          /* 1: OTHER */
+[SENSOR_OTHER] = {
        .n3 =
                {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
        .n4 = n4_other,
@@ -416,14 +406,12 @@ static const struct additional_sensor_data sensor_data[] = {
        .data3 =
                {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
                 0xd9},
-       .data4 =
-               {0x66, 0x00, 0xa8, 0xa8},
        .data5 =
                {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
        .stream =
                {0x0b, 0x04, 0x0a, 0x00},
     },
-    {                          /* 2: TAS5130A */
+[SENSOR_TAS5130A] = {
        .n3 =
                {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
        .n4 = n4_tas5130a,
@@ -440,14 +428,12 @@ static const struct additional_sensor_data sensor_data[] = {
        .data3 =
                {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
                 0xe0},
-       .data4 =        /* Freq (50/60Hz). Splitted for test purpose */
-               {0x66, 0x00, 0xa8, 0xe8},
        .data5 =
                {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
        .stream =
                {0x0b, 0x04, 0x0a, 0x40},
     },
-    {                          /* 3: LT168G */
+[SENSOR_LT168G] = {
        .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
        .n4 = n4_lt168g,
        .n4sz = sizeof n4_lt168g,
@@ -460,7 +446,6 @@ static const struct additional_sensor_data sensor_data[] = {
                 0xff},
        .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
                 0xff},
-       .data4 = {0x66, 0x41, 0xa8, 0xf0},
        .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
        .stream = {0x0b, 0x04, 0x0a, 0x28},
     },
@@ -469,6 +454,15 @@ static const struct additional_sensor_data sensor_data[] = {
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
+static char *effects_control[MAX_EFFECTS] = {
+       "Normal",
+       "Emboss",               /* disabled */
+       "Monochrome",
+       "Sepia",
+       "Sketch",
+       "Sun Effect",           /* disabled */
+       "Negative",
+};
 static const u8 effects_table[MAX_EFFECTS][6] = {
        {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},   /* Normal */
        {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},   /* Repujar */
@@ -480,40 +474,41 @@ static const u8 effects_table[MAX_EFFECTS][6] = {
 };
 
 static const u8 gamma_table[GAMMA_MAX][17] = {
-       {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9,        /* 0 */
-        0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
+/* gamma table from cam1690.ini */
+       {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,        /* 0 */
+        0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
         0xff},
-       {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad,        /* 1 */
-        0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
+       {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,        /* 1 */
+        0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
         0xff},
-       {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6,        /* 2 */
-        0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
+       {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,        /* 2 */
+        0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
         0xff},
-       {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e,        /* 3 */
-        0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
+       {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,        /* 3 */
+        0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
         0xff},
-       {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95,        /* 4 */
-        0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
+       {0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a,        /* 4 */
+        0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
         0xff},
-       {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87,        /* 5 */
-        0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
+       {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,        /* 5 */
+        0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
         0xff},
-       {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67,        /* 6 */
+       {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,        /* 6 */
         0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
         0xff},
-       {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70,        /* 7 */
+       {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,        /* 7 */
         0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
         0xff},
-       {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79,        /* 8 */
-        0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
+       {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,        /* 8 */
+        0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
         0xff},
-       {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84,        /* 9 */
-        0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
+       {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,        /* 9 */
+        0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
         0xff},
-       {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e,        /* 10 */
-        0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
+       {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,        /* 10 */
+        0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
         0xff},
-       {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b,        /* 11 */
+       {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,        /* 11 */
         0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
         0xff},
        {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,        /* 12 */
@@ -577,12 +572,11 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
        } else {
                u8 *tmpbuf;
 
-               tmpbuf = kmalloc(len, GFP_KERNEL);
+               tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
                if (!tmpbuf) {
                        err("Out of memory");
                        return;
                }
-               memcpy(tmpbuf, buffer, len);
                usb_control_msg(gspca_dev->dev,
                                usb_sndctrlpipe(gspca_dev->dev, 0),
                                0,
@@ -625,7 +619,6 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
                kfree(tmpbuf);
 }
 
-/* Reported as OM6802*/
 static void om6802_sensor_init(struct gspca_dev *gspca_dev)
 {
        int i;
@@ -703,12 +696,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->autogain = AUTOGAIN_DEF;
        sd->mirror = MIRROR_DEF;
        sd->freq = FREQ_DEF;
-       sd->whitebalance = WHITE_BALANCE_DEF;
+       sd->awb = AWB_DEF;
        sd->sharpness = SHARPNESS_DEF;
        sd->effect = EFFECTS_DEF;
-       sd->red_balance = RED_BALANCE_DEF;
-       sd->blue_balance = BLUE_BALANCE_DEF;
-       sd->global_gain = global_gain_DEF;
+       sd->red_gain = RED_GAIN_DEF;
+       sd->blue_gain = BLUE_GAIN_DEF;
+       sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
 
        return 0;
 }
@@ -761,40 +754,59 @@ static void setgamma(struct gspca_dev *gspca_dev)
        reg_w_ixbuf(gspca_dev, 0x90,
                gamma_table[sd->gamma], sizeof gamma_table[0]);
 }
-static void setglobalgain(struct gspca_dev *gspca_dev)
-{
 
+static void setRGB(struct gspca_dev *gspca_dev)
+{
        struct sd *sd = (struct sd *) gspca_dev;
-       reg_w(gspca_dev, (sd->red_balance  << 8) + 0x87);
-       reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88);
-       reg_w(gspca_dev, (sd->global_gain  << 8) + 0x89);
+       u8 all_gain_reg[6] =
+               {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
+
+       all_gain_reg[1] = sd->red_gain;
+       all_gain_reg[3] = sd->blue_gain;
+       all_gain_reg[5] = sd->green_gain;
+       reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
 }
 
-/* Generic fnc for r/b balance, exposure and whitebalance */
-static void setbalance(struct gspca_dev *gspca_dev)
+/* Generic fnc for r/b balance, exposure and awb */
+static void setawb(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u16 reg80;
 
-       /* on whitebalance leave defaults values */
-       if (sd->whitebalance) {
-               reg_w(gspca_dev, 0x3c80);
-       } else {
-               reg_w(gspca_dev, 0x3880);
+       reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
+
+       /* on awb leave defaults values */
+       if (!sd->awb) {
                /* shoud we wait here.. */
-               /* update and reset 'global gain' with webcam parameters */
-               sd->red_balance = reg_r(gspca_dev, 0x0087);
-               sd->blue_balance = reg_r(gspca_dev, 0x0088);
-               sd->global_gain = reg_r(gspca_dev, 0x0089);
-               setglobalgain(gspca_dev);
+               /* update and reset RGB gains with webcam values */
+               sd->red_gain = reg_r(gspca_dev, 0x0087);
+               sd->blue_gain = reg_r(gspca_dev, 0x0088);
+               sd->green_gain = reg_r(gspca_dev, 0x0089);
+               reg80 &= ~0x0400;               /* AWB off */
        }
-
+       reg_w(gspca_dev, reg80);
+       reg_w(gspca_dev, reg80);
 }
 
-
-
-static void setwhitebalance(struct gspca_dev *gspca_dev)
+static void init_gains(struct gspca_dev *gspca_dev)
 {
-       setbalance(gspca_dev);
+       struct sd *sd = (struct sd *) gspca_dev;
+       u16 reg80;
+       u8 all_gain_reg[8] =
+               {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
+
+       all_gain_reg[1] = sd->red_gain;
+       all_gain_reg[3] = sd->blue_gain;
+       all_gain_reg[5] = sd->green_gain;
+       reg80 = sensor_data[sd->sensor].reg80;
+       if (!sd->awb)
+               reg80 &= ~0x04;
+       all_gain_reg[7] = reg80;
+       reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
+
+       reg_w(gspca_dev, (sd->red_gain  << 8) + 0x87);
+       reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
+       reg_w(gspca_dev, (sd->green_gain  << 8) + 0x89);
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -807,6 +819,38 @@ static void setsharpness(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, reg_to_write);
 }
 
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 reg66;
+       u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
+
+       switch (sd->sensor) {
+       case SENSOR_LT168G:
+               if (sd->freq != 0)
+                       freq[3] = 0xa8;
+               reg66 = 0x41;
+               break;
+       case SENSOR_OM6802:
+               reg66 = 0xca;
+               break;
+       default:
+               reg66 = 0x40;
+               break;
+       }
+       switch (sd->freq) {
+       case 0:                         /* no flicker */
+               freq[3] = 0xf0;
+               break;
+       case 2:                         /* 60Hz */
+               reg66 &= ~0x40;
+               break;
+       }
+       freq[1] = reg66;
+
+       reg_w_buf(gspca_dev, freq, sizeof freq);
+}
+
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
@@ -901,13 +945,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
        setgamma(gspca_dev);
        setcolors(gspca_dev);
        setsharpness(gspca_dev);
-       setwhitebalance(gspca_dev);
-
-       reg_w(gspca_dev, 0x2087);       /* tied to white balance? */
-       reg_w(gspca_dev, 0x2088);
-       reg_w(gspca_dev, 0x2089);
+       init_gains(gspca_dev);
+       setfreq(gspca_dev);
 
-       reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
        reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
        reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
        reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
@@ -926,16 +966,16 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void setflip(struct gspca_dev *gspca_dev)
+static void setmirror(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 flipcmd[8] =
+       u8 hflipcmd[8] =
                {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 
        if (sd->mirror)
-               flipcmd[3] = 0x01;
+               hflipcmd[3] = 0x01;
 
-       reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
+       reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
 }
 
 static void seteffect(struct gspca_dev *gspca_dev)
@@ -956,17 +996,6 @@ static void seteffect(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0xfaa6);
 }
 
-static void setlightfreq(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
-
-       if (sd->freq == 2)      /* 60hz */
-               freq[1] = 0x00;
-
-       reg_w_buf(gspca_dev, freq, sizeof freq);
-}
-
 /* Is this really needed?
  * i added some module parameters for test with some users */
 static void poll_sensor(struct gspca_dev *gspca_dev)
@@ -979,9 +1008,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
        static const u8 poll2[] =
                {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
                 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
-       static const u8 poll3[] =
-               {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
-       static const u8 poll4[] =
+       static const u8 noise03[] =     /* (some differences / ms-drv) */
                {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
                 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
                 0xc2, 0x80, 0xc3, 0x10};
@@ -989,8 +1016,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
        PDEBUG(D_STREAM, "[Sensor requires polling]");
        reg_w_buf(gspca_dev, poll1, sizeof poll1);
        reg_w_buf(gspca_dev, poll2, sizeof poll2);
-       reg_w_buf(gspca_dev, poll3, sizeof poll3);
-       reg_w_buf(gspca_dev, poll4, sizeof poll4);
+       reg_w_buf(gspca_dev, noise03, sizeof noise03);
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
@@ -1025,12 +1051,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        case SENSOR_OM6802:
                om6802_sensor_init(gspca_dev);
                break;
-       case SENSOR_LT168G:
-               break;
-       case SENSOR_OTHER:
-               break;
-       default:
-/*     case SENSOR_TAS5130A: */
+       case SENSOR_TAS5130A:
                i = 0;
                for (;;) {
                        reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
@@ -1047,7 +1068,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        }
        sensor = &sensor_data[sd->sensor];
-       reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+       setfreq(gspca_dev);
        reg_r(gspca_dev, 0x0012);
        reg_w_buf(gspca_dev, t2, sizeof t2);
        reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
@@ -1080,7 +1101,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
-       static u8 ffd9[] = { 0xff, 0xd9 };
+       int pkt_type;
 
        if (data[0] == 0x5a) {
                /* Control Packet, after this came the header again,
@@ -1090,84 +1111,88 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
        data += 2;
        len -= 2;
-       if (data[0] == 0xff && data[1] == 0xd8) {
-               /* extra bytes....., could be processed too but would be
-                * a waste of time, right now leave the application and
-                * libjpeg do it for ourserlves.. */
-               gspca_frame_add(gspca_dev, LAST_PACKET,
-                                       ffd9, 2);
-               gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
-               return;
-       }
-
-       if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
-               /* Just in case, i have seen packets with the marker,
-                * other's do not include it... */
-               len -= 2;
-       }
-       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+       if (data[0] == 0xff && data[1] == 0xd8)
+               pkt_type = FIRST_PACKET;
+       else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
+               pkt_type = LAST_PACKET;
+       else
+               pkt_type = INTER_PACKET;
+       gspca_frame_add(gspca_dev, pkt_type, data, len);
 }
 
-
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->blue_balance = val;
+       sd->blue_gain = val;
        if (gspca_dev->streaming)
                reg_w(gspca_dev, (val << 8) + 0x88);
        return 0;
 }
 
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->blue_balance;
+       *val = sd->blue_gain;
        return 0;
 }
 
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->red_balance = val;
+       sd->red_gain = val;
        if (gspca_dev->streaming)
                reg_w(gspca_dev, (val << 8) + 0x87);
 
        return 0;
 }
 
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->red_balance;
+       *val = sd->red_gain;
        return 0;
 }
 
-
-
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u16 psg, nsg;
+
+       psg = sd->red_gain + sd->blue_gain + sd->green_gain;
+       nsg = val * 3;
+       sd->red_gain = sd->red_gain * nsg / psg;
+       if (sd->red_gain > 0x40)
+               sd->red_gain = 0x40;
+       else if (sd->red_gain < 0x10)
+               sd->red_gain = 0x10;
+       sd->blue_gain = sd->blue_gain * nsg / psg;
+       if (sd->blue_gain > 0x40)
+               sd->blue_gain = 0x40;
+       else if (sd->blue_gain < 0x10)
+               sd->blue_gain = 0x10;
+       sd->green_gain = sd->green_gain * nsg / psg;
+       if (sd->green_gain > 0x40)
+               sd->green_gain = 0x40;
+       else if (sd->green_gain < 0x10)
+               sd->green_gain = 0x10;
 
-       sd->global_gain = val;
        if (gspca_dev->streaming)
-               setglobalgain(gspca_dev);
-
+               setRGB(gspca_dev);
        return 0;
 }
 
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->global_gain;
+       *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
        return 0;
 }
 
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1186,35 +1211,35 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
        return *val;
 }
 
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->whitebalance = val;
+       sd->awb = val;
        if (gspca_dev->streaming)
-               setwhitebalance(gspca_dev);
+               setawb(gspca_dev);
        return 0;
 }
 
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->whitebalance;
+       *val = sd->awb;
        return *val;
 }
 
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->mirror = val;
        if (gspca_dev->streaming)
-               setflip(gspca_dev);
+               setmirror(gspca_dev);
        return 0;
 }
 
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1300,7 +1325,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
 
        sd->freq = val;
        if (gspca_dev->streaming)
-               setlightfreq(gspca_dev);
+               setfreq(gspca_dev);
        return 0;
 }
 
@@ -1368,7 +1393,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        case V4L2_CID_EFFECTS:
                if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
                        strncpy((char *) menu->name,
-                               effects_control[menu->index], 32);
+                               effects_control[menu->index],
+                               sizeof menu->name);
                        return 0;
                }
                break;
index c7b6eb1e04d56b2b58fa4217e762b8f3dc50881c..d9c5bf3449d43ed556b859959e293d37804edf80 100644 (file)
@@ -30,29 +30,46 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       __u16 brightness;
+       __u16 exposure;
+       __u16 gain;
 
        __u8 packet;
 };
 
 /* 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_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(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 const struct ctrl sd_ctrls[] = {
        {
         {
-         .id = V4L2_CID_BRIGHTNESS,
+         .id = V4L2_CID_EXPOSURE,
          .type = V4L2_CTRL_TYPE_INTEGER,
-         .name = "Brightness",
+         .name = "Exposure",
          .minimum = 1,
-         .maximum = 0x15f,     /* = 352 - 1 */
+         .maximum = 0x18f,
          .step = 1,
-#define BRIGHTNESS_DEF 0x14c
-         .default_value = BRIGHTNESS_DEF,
+#define EXPOSURE_DEF 0x18f
+         .default_value = EXPOSURE_DEF,
          },
-        .set = sd_setbrightness,
-        .get = sd_getbrightness,
+        .set = sd_setexposure,
+        .get = sd_getexposure,
+        },
+       {
+        {
+         .id = V4L2_CID_GAIN,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Gain",
+         .minimum = 0,
+         .maximum = 0x7ff,
+         .step = 1,
+#define GAIN_DEF 0x100
+         .default_value = GAIN_DEF,
+         },
+        .set = sd_setgain,
+        .get = sd_getgain,
         },
 };
 
@@ -92,6 +109,14 @@ static const struct v4l2_pix_format sif_mode[] = {
 #define R14_AD_ROW_BEGINL 0x14
 #define R15_AD_ROWBEGINH  0x15
 #define R1C_AD_EXPOSE_TIMEL 0x1c
+#define R20_GAIN_G1L   0x20
+#define R21_GAIN_G1H   0x21
+#define R22_GAIN_RL    0x22
+#define R23_GAIN_RH    0x23
+#define R24_GAIN_BL    0x24
+#define R25_GAIN_BH    0x25
+#define R26_GAIN_G2L   0x26
+#define R27_GAIN_G2H   0x27
 #define R28_QUANT      0x28
 #define R29_LINE       0x29
 #define R2C_POLARITY   0x2c
@@ -129,18 +154,6 @@ static const u8 eeprom_data[][3] = {
        {0x05, 0x09, 0xf1},
 };
 
-static int reg_r(struct gspca_dev *gspca_dev,
-                __u16 index)
-{
-       usb_control_msg(gspca_dev->dev,
-                       usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       0x03,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0,      /* value */
-                       index, gspca_dev->usb_buf, 1,
-                       500);
-       return gspca_dev->usb_buf[0];
-}
 
 /* write 1 byte */
 static void reg_w1(struct gspca_dev *gspca_dev,
@@ -183,7 +196,6 @@ static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
        }
        reg_w1(gspca_dev, R07_TABLE_LEN, i);
        reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
-       msleep(10);
 }
 
 /* this function is called at probe time */
@@ -197,53 +209,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam->cam_mode = sif_mode;
        cam->nmodes = ARRAY_SIZE(sif_mode);
 
-       sd->brightness = BRIGHTNESS_DEF;
+       sd->exposure = EXPOSURE_DEF;
+       sd->gain = GAIN_DEF;
        return 0;
 }
 
-static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
-{
-       int i;
-       static u8 reg_tb[] = {
-               R0C_AD_WIDTHL,
-               R0D_AD_WIDTHH,
-               R28_QUANT,
-               R29_LINE,
-               R2C_POLARITY,
-               R2D_POINT,
-               R2E_POINTH,
-               R2F_POINTB,
-               R30_POINTBH,
-               R2A_HIGH_BUDGET,
-               R2B_LOW_BUDGET,
-               R34_VID,
-               R35_VIDH,
-               R36_PID,
-               R37_PIDH,
-               R83_AD_IDH,
-               R10_AD_COL_BEGINL,
-               R11_AD_COL_BEGINH,
-               R14_AD_ROW_BEGINL,
-               R15_AD_ROWBEGINH,
-               0
-       };
-
-       i = 0;
-       do {
-               reg_r(gspca_dev, reg_tb[i]);
-               i++;
-       } while (reg_tb[i] != 0);
-}
-
 static void tv_8532_setReg(struct gspca_dev *gspca_dev)
 {
-       reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
-                                               /* begin active line */
-       reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
-                                               /* mirror and digital gain */
-       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
-                                               /* = 0x84 */
-
        reg_w1(gspca_dev, R3B_Test3, 0x0a);     /* Test0Sel = 10 */
        /******************************************************/
        reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
@@ -255,100 +227,43 @@ static void tv_8532_setReg(struct gspca_dev *gspca_dev)
                                                /* mirror and digital gain */
        reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
 
-       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
        reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
-
-       reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
-
        reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
        reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
                                                /* = 0x84 */
 }
 
-static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
-{
-       int i;
-
-       /* strange polling from tgc */
-       for (i = 0; i < 10; i++) {
-               reg_w1(gspca_dev, R2C_POLARITY, 0x10);
-               reg_w1(gspca_dev, R00_PART_CONTROL,
-                               LATENT_CHANGE | EXPO_CHANGE);
-               reg_w1(gspca_dev, R31_UPD, 0x01);
-       }
-}
-
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
        tv_8532WriteEEprom(gspca_dev);
 
-       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32);       /* slope begin 1,7V,
-                                                        * slope rate 2 */
-       reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
-       tv_8532ReadRegisters(gspca_dev);
-       reg_w1(gspca_dev, R3B_Test3, 0x0b);
-       reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
-       reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
-       reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);
-       reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
-
-       /*******************************************************************/
-       reg_w1(gspca_dev, R28_QUANT, 0x90);
-                                       /* no compress - fixed Q - quant 0 */
-       reg_w1(gspca_dev, R29_LINE, 0x81);
-                                       /* 0x84; // CIF | 4 packet 0x29 */
-
-       /************************************************/
-       reg_w1(gspca_dev, R2C_POLARITY, 0x10);
-                                               /* 0x48; //0x08; 0x2c */
-       reg_w1(gspca_dev, R2D_POINT, 0x14);
-                                               /* 0x38; 0x2d */
-       reg_w1(gspca_dev, R2E_POINTH, 0x01);
-                                               /* 0x04; 0x2e */
-       reg_w1(gspca_dev, R2F_POINTB, 0x12);
-                                               /* 0x04; 0x2f */
-       reg_w1(gspca_dev, R30_POINTBH, 0x01);
-                                               /* 0x04; 0x30 */
-       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
-                                               /* 0x00<-0x84 */
-       /*************************************************/
-       reg_w1(gspca_dev, R31_UPD, 0x01);       /* update registers */
-       msleep(200);
-       reg_w1(gspca_dev, R31_UPD, 0x00);               /* end update */
-       /*************************************************/
-       tv_8532_setReg(gspca_dev);
-       /*************************************************/
-       reg_w1(gspca_dev, R3B_Test3, 0x0b);     /* Test0Sel = 11 = GPIO */
-       /*************************************************/
-       tv_8532_setReg(gspca_dev);
-       /*************************************************/
-       tv_8532_PollReg(gspca_dev);
        return 0;
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness);
+       reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure);
        reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
                                                /* 0x84 */
 }
 
-/* -- start the camera -- */
-static int sd_start(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32);       /* slope begin 1,7V,
-                                                        * slope rate 2 */
-       reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
-       tv_8532ReadRegisters(gspca_dev);
-       reg_w1(gspca_dev, R3B_Test3, 0x0b);
+       reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain);
+       reg_w2(gspca_dev, R22_GAIN_RL, sd->gain);
+       reg_w2(gspca_dev, R24_GAIN_BL, sd->gain);
+       reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain);
+}
 
-       reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
-       setbrightness(gspca_dev);
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);         /* 0x20; 0x0c */
        reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
@@ -371,19 +286,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, R2E_POINTH, 0x01);
        reg_w1(gspca_dev, R2F_POINTB, 0x12);
        reg_w1(gspca_dev, R30_POINTBH, 0x01);
-       reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+
+       tv_8532_setReg(gspca_dev);
+
+       setexposure(gspca_dev);
+       setgain(gspca_dev);
+
        /************************************************/
        reg_w1(gspca_dev, R31_UPD, 0x01);       /* update registers */
        msleep(200);
-       reg_w1(gspca_dev, R31_UPD, 0x00);               /* end update */
-       /************************************************/
-       tv_8532_setReg(gspca_dev);
-       /************************************************/
-       reg_w1(gspca_dev, R3B_Test3, 0x0b);     /* Test0Sel = 11 = GPIO */
-       /************************************************/
-       tv_8532_setReg(gspca_dev);
-       /************************************************/
-       tv_8532_PollReg(gspca_dev);
        reg_w1(gspca_dev, R31_UPD, 0x00);       /* end update */
 
        gspca_dev->empty_packet = 0;            /* check the empty packets */
@@ -428,21 +339,39 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        data + gspca_dev->width + 5, gspca_dev->width);
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+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_setgain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->brightness = val;
+       sd->gain = val;
        if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
+               setgain(gspca_dev);
        return 0;
 }
 
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->brightness;
+       *val = sd->gain;
        return 0;
 }
 
index 732c3dfe46fffeb57f7109c27ad08829c38a52b2..031266a4081bfe0eee9a317f6f73c1f3cf31bce0 100644 (file)
@@ -2748,11 +2748,11 @@ static const u8 poxxxx_init_common[][4] = {
        {0xb3, 0x04, 0x15, 0xcc},
        {0xb3, 0x20, 0x00, 0xcc},
        {0xb3, 0x21, 0x00, 0xcc},
-       {0xb3, 0x22, 0x04, 0xcc},
+       {0xb3, 0x22, 0x04, 0xcc},       /* sensor height = 1024 */
        {0xb3, 0x23, 0x00, 0xcc},
        {0xb3, 0x14, 0x00, 0xcc},
        {0xb3, 0x15, 0x00, 0xcc},
-       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x16, 0x04, 0xcc},       /* sensor width = 1280 */
        {0xb3, 0x17, 0xff, 0xcc},
        {0xb3, 0x2c, 0x03, 0xcc},
        {0xb3, 0x2d, 0x56, 0xcc},
@@ -2919,7 +2919,7 @@ static const u8 poxxxx_initVGA[][4] = {
        {0x00, 0x20, 0x11, 0xaa},
        {0x00, 0x33, 0x38, 0xaa},
        {0x00, 0xbb, 0x0d, 0xaa},
-       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},       /* change to 640x480 */
        {0xb3, 0x23, 0xe0, 0xcc},
        {0xb3, 0x16, 0x02, 0xcc},
        {0xb3, 0x17, 0x7f, 0xcc},
@@ -2935,7 +2935,7 @@ static const u8 poxxxx_initQVGA[][4] = {
        {0x00, 0x20, 0x33, 0xaa},
        {0x00, 0x33, 0x38, 0xaa},
        {0x00, 0xbb, 0x0d, 0xaa},
-       {0xb3, 0x22, 0x00, 0xcc},
+       {0xb3, 0x22, 0x00, 0xcc},       /* change to 320x240 */
        {0xb3, 0x23, 0xf0, 0xcc},
        {0xb3, 0x16, 0x01, 0xcc},
        {0xb3, 0x17, 0x3f, 0xcc},
@@ -3068,37 +3068,84 @@ static const struct sensor_info vc0323_probe_data[] = {
 };
 
 /* read 'len' bytes in gspca_dev->usb_buf */
-static void reg_r(struct gspca_dev *gspca_dev,
+static void reg_r_i(struct gspca_dev *gspca_dev,
                  u16 req,
                  u16 index,
                  u16 len)
 {
-       usb_control_msg(gspca_dev->dev,
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
                        req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        1,                      /* value */
                        index, gspca_dev->usb_buf, len,
                        500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_r err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+static void reg_r(struct gspca_dev *gspca_dev,
+                 u16 req,
+                 u16 index,
+                 u16 len)
+{
+       reg_r_i(gspca_dev, req, index, len);
+#ifdef GSPCA_DEBUG
+       if (gspca_dev->usb_err < 0)
+               return;
+       if (len == 1)
+               PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index,
+                               gspca_dev->usb_buf[0]);
+       else
+               PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x",
+                               req, index,
+                               gspca_dev->usb_buf[0],
+                               gspca_dev->usb_buf[1],
+                               gspca_dev->usb_buf[2]);
+#endif
 }
 
-static void reg_w(struct usb_device *dev,
+static void reg_w_i(struct gspca_dev *gspca_dev,
                            u16 req,
                            u16 value,
                            u16 index)
 {
-       usb_control_msg(dev,
-                       usb_sndctrlpipe(dev, 0),
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
                        req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index, NULL, 0,
                        500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+static void reg_w(struct gspca_dev *gspca_dev,
+                           u16 req,
+                           u16 value,
+                           u16 index)
+{
+#ifdef GSPCA_DEBUG
+       if (gspca_dev->usb_err < 0)
+               return;
+       PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+#endif
+       reg_w_i(gspca_dev, req, value, index);
 }
 
 static u16 read_sensor_register(struct gspca_dev *gspca_dev,
                                u16 address)
 {
-       struct usb_device *dev = gspca_dev->dev;
        u8 ldata, mdata, hdata;
        int retry = 50;
 
@@ -3108,8 +3155,8 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
                        gspca_dev->usb_buf[0]);
                return 0;
        }
-       reg_w(dev, 0xa0, address, 0xb33a);
-       reg_w(dev, 0xa0, 0x02, 0xb339);
+       reg_w(gspca_dev, 0xa0, address, 0xb33a);
+       reg_w(gspca_dev, 0xa0, 0x02, 0xb339);
 
        do {
                reg_r(gspca_dev, 0xa1, 0xb33b, 1);
@@ -3136,15 +3183,15 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
 static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
        int i, n;
        u16 value;
        const struct sensor_info *ptsensor_info;
 
 /*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
        if (sd->flags & FL_SAMSUNG) {
-               reg_w(dev, 0xa0, 0x01, 0xb301);
-               reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+               reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+               reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+                                               /* select the back sensor */
        }
 
        reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -3158,13 +3205,13 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
                n = ARRAY_SIZE(vc0323_probe_data);
        }
        for (i = 0; i < n; i++) {
-               reg_w(dev, 0xa0, 0x02, 0xb334);
-               reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
-               reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
-               reg_w(dev, 0xa0, 0x01, 0xb308);
-               reg_w(dev, 0xa0, 0x0c, 0xb309);
-               reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
-               reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+               reg_w(gspca_dev, 0xa0, 0x02, 0xb334);
+               reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300);
+               reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300);
+               reg_w(gspca_dev, 0xa0, 0x01, 0xb308);
+               reg_w(gspca_dev, 0xa0, 0x0c, 0xb309);
+               reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+               reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301);
                value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
                if (value == 0 && ptsensor_info->IdAdd == 0x82)
                        value = read_sensor_register(gspca_dev, 0x83);
@@ -3192,26 +3239,33 @@ static void i2c_write(struct gspca_dev *gspca_dev,
                        u8 reg, const u8 *val,
                        u8 size)                /* 1 or 2 */
 {
-       struct usb_device *dev = gspca_dev->dev;
        int retry;
 
-       reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+#ifdef GSPCA_DEBUG
+       if (gspca_dev->usb_err < 0)
+               return;
+       if (size == 1)
+               PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
+       else
+               PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
+#endif
+       reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
 /*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
-       reg_w(dev, 0xa0, size, 0xb334);
-       reg_w(dev, 0xa0, reg, 0xb33a);
-       reg_w(dev, 0xa0, val[0], 0xb336);
+       reg_w_i(gspca_dev, 0xa0, size, 0xb334);
+       reg_w_i(gspca_dev, 0xa0, reg, 0xb33a);
+       reg_w_i(gspca_dev, 0xa0, val[0], 0xb336);
        if (size > 1)
-               reg_w(dev, 0xa0, val[1], 0xb337);
-       reg_w(dev, 0xa0, 0x01, 0xb339);
+               reg_w_i(gspca_dev, 0xa0, val[1], 0xb337);
+       reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339);
        retry = 4;
        do {
-               reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+               reg_r_i(gspca_dev, 0xa1, 0xb33b, 1);
                if (gspca_dev->usb_buf[0] == 0)
                        break;
                msleep(20);
        } while (--retry > 0);
        if (retry <= 0)
-               PDEBUG(D_ERR, "i2c_write failed");
+               PDEBUG(D_ERR, "i2c_write timeout");
 }
 
 static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -3221,13 +3275,12 @@ static void put_tab_to_reg(struct gspca_dev *gspca_dev,
        u16 ad = addr;
 
        for (j = 0; j < tabsize; j++)
-               reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+               reg_w(gspca_dev, 0xa0, tab[j], ad++);
 }
 
 static void usb_exchange(struct gspca_dev *gspca_dev,
                        const u8 data[][4])
 {
-       struct usb_device *dev = gspca_dev->dev;
        int i = 0;
 
        for (;;) {
@@ -3235,7 +3288,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
                default:
                        return;
                case 0xcc:                      /* normal write */
-                       reg_w(dev, 0xa0, data[i][2],
+                       reg_w(gspca_dev, 0xa0, data[i][2],
                                        (data[i][0]) << 8 | data[i][1]);
                        break;
                case 0xaa:                      /* i2c op */
@@ -3259,7 +3312,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
        struct cam *cam;
        int sensor;
        static u8 npkt[] = {    /* number of packets per ISOC message */
@@ -3363,13 +3415,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        if (sd->sensor == SENSOR_OV7670)
                sd->flags |= FL_HFLIP | FL_VFLIP;
 
-       if (sd->bridge == BRIDGE_VC0321) {
-               reg_r(gspca_dev, 0x8a, 0, 3);
-               reg_w(dev, 0x87, 0x00, 0x0f0f);
-
-               reg_r(gspca_dev, 0x8b, 0, 3);
-               reg_w(dev, 0x88, 0x00, 0x0202);
-       }
        return 0;
 }
 
@@ -3378,15 +3423,21 @@ static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (sd->sensor == SENSOR_POxxxx) {
-               reg_r(gspca_dev, 0xa1, 0xb300, 1);
-               if (gspca_dev->usb_buf[0] != 0) {
-                       reg_w(gspca_dev->dev, 0xa0, 0x26, 0xb300);
-                       reg_w(gspca_dev->dev, 0xa0, 0x04, 0xb300);
-                       reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb300);
+       if (sd->bridge == BRIDGE_VC0321) {
+               reg_r(gspca_dev, 0x8a, 0, 3);
+               reg_w(gspca_dev, 0x87, 0x00, 0x0f0f);
+               reg_r(gspca_dev, 0x8b, 0, 3);
+               reg_w(gspca_dev, 0x88, 0x00, 0x0202);
+               if (sd->sensor == SENSOR_POxxxx) {
+                       reg_r(gspca_dev, 0xa1, 0xb300, 1);
+                       if (gspca_dev->usb_buf[0] != 0) {
+                               reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+                               reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+                               reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
+                       }
                }
        }
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
@@ -3516,17 +3567,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 /*fixme: back sensor only*/
        if (sd->flags & FL_SAMSUNG) {
-               reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
-               reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
-               reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+               reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+               reg_w(gspca_dev, 0xa9, 0x8348, 0x000e);
+               reg_w(gspca_dev, 0xa9, 0x0000, 0x001a);
        }
 
        /* Assume start use the good resolution from gspca_dev->mode */
        if (sd->bridge == BRIDGE_VC0321) {
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
-               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+               reg_w(gspca_dev, 0xa0, 0xff, 0xbfec);
+               reg_w(gspca_dev, 0xa0, 0xff, 0xbfed);
+               reg_w(gspca_dev, 0xa0, 0xff, 0xbfee);
+               reg_w(gspca_dev, 0xa0, 0xff, 0xbfef);
                sd->image_offset = 46;
        } else {
                if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
@@ -3617,7 +3668,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                        init = poxxxx_initVGA;
                usb_exchange(gspca_dev, init);
                reg_r(gspca_dev, 0x8c, 0x0000, 3);
-               reg_w(gspca_dev->dev, 0xa0,
+               reg_w(gspca_dev, 0xa0,
                                gspca_dev->usb_buf[2] & 1 ? 0 : 1,
                                0xb35c);
                msleep(300);
@@ -3635,10 +3686,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
                switch (sd->sensor) {
                case SENSOR_PO1200:
                case SENSOR_HV7131R:
-                       reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+                       reg_w(gspca_dev, 0x89, 0x0400, 0x1415);
                        break;
                case SENSOR_MI1310_SOC:
-                       reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
+                       reg_w(gspca_dev, 0x89, 0x058c, 0x0000);
                        break;
                }
                msleep(100);
@@ -3648,9 +3699,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
        }
        switch (sd->sensor) {
        case SENSOR_OV7670:
-               reg_w(gspca_dev->dev, 0x87, 0xffff, 0xffff);
-               reg_w(gspca_dev->dev, 0x88, 0xff00, 0xf0f1);
-               reg_w(gspca_dev->dev, 0xa0, 0x0000, 0xbfff);
+               reg_w(gspca_dev, 0x87, 0xffff, 0xffff);
+               reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1);
+               reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff);
                break;
        case SENSOR_POxxxx:
                setcolors(gspca_dev);
@@ -3659,51 +3710,49 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
                /* led on */
                msleep(80);
-               reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+               reg_w(gspca_dev, 0x89, 0xffff, 0xfdff);
                usb_exchange(gspca_dev, poxxxx_init_end_2);
                break;
        }
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       struct usb_device *dev = gspca_dev->dev;
        struct sd *sd = (struct sd *) gspca_dev;
 
        switch (sd->sensor) {
        case SENSOR_MI1310_SOC:
-               reg_w(dev, 0x89, 0x058c, 0x00ff);
+               reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
                break;
        case SENSOR_POxxxx:
                return;
        default:
                if (!(sd->flags & FL_SAMSUNG))
-                       reg_w(dev, 0x89, 0xffff, 0xffff);
+                       reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
                break;
        }
-       reg_w(dev, 0xa0, 0x01, 0xb301);
-       reg_w(dev, 0xa0, 0x09, 0xb003);
+       reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+       reg_w(gspca_dev, 0xa0, 0x09, 0xb003);
 }
 
 /* called on streamoff with alt 0 and on disconnect */
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-       struct usb_device *dev = gspca_dev->dev;
        struct sd *sd = (struct sd *) gspca_dev;
 
        if (!gspca_dev->present)
                return;
 /*fixme: is this useful?*/
        if (sd->sensor == SENSOR_MI1310_SOC)
-               reg_w(dev, 0x89, 0x058c, 0x00ff);
+               reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
        else if (!(sd->flags & FL_SAMSUNG))
-               reg_w(dev, 0x89, 0xffff, 0xffff);
+               reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
 
        if (sd->sensor == SENSOR_POxxxx) {
-               reg_w(dev, 0xa0, 0x26, 0xb300);
-               reg_w(dev, 0xa0, 0x04, 0xb300);
-               reg_w(dev, 0xa0, 0x00, 0xb300);
+               reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+               reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+               reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
        }
 }
 
@@ -3726,17 +3775,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        /* The vc0321 sends some additional data after sending the complete
         * frame, we ignore this. */
        if (sd->bridge == BRIDGE_VC0321) {
-               struct gspca_frame *frame;
-               int l;
+               int size, l;
 
-               frame = gspca_get_i_frame(gspca_dev);
-               if (frame == NULL) {
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-                       return;
-               }
-               l = frame->data_end - frame->data;
-               if (len > frame->v4l2_buf.length - l)
-                       len = frame->v4l2_buf.length - l;
+               l = gspca_dev->image_len;
+               size = gspca_dev->frsz;
+               if (len > size - l)
+                       len = size - l;
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
@@ -3748,7 +3792,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
        sd->brightness = val;
        if (gspca_dev->streaming)
                setbrightness(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3766,7 +3810,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
        sd->contrast = val;
        if (gspca_dev->streaming)
                setcontrast(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3784,7 +3828,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
        sd->colors = val;
        if (gspca_dev->streaming)
                setcolors(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3802,7 +3846,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
        sd->hflip = val;
        if (gspca_dev->streaming)
                sethvflip(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3820,7 +3864,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
        sd->vflip = val;
        if (gspca_dev->streaming)
                sethvflip(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3838,7 +3882,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
        sd->lightfreq = val;
        if (gspca_dev->streaming)
                setlightfreq(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3856,7 +3900,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
        sd->sharpness = val;
        if (gspca_dev->streaming)
                setsharpness(gspca_dev);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
index 2fffe203bed876fdcaf4713ffe32edabd4b5d39f..38a68591ce48be033244590ce5a5bf9859bf5e7b 100644 (file)
    the sensor drivers to v4l2 sub drivers, and properly split of this
    driver from ov519.c */
 
-/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
-#define CONEX_CAM
-#include "jpeg.h"
-
 #define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
 
-#define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET)
-#define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET)
+#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET])
+#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET])
 
 static const struct v4l2_pix_format w9968cf_vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
@@ -509,11 +505,6 @@ static int w9968cf_mode_init_regs(struct sd *sd)
        if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
            V4L2_PIX_FMT_JPEG) {
                /* We may get called multiple times (usb isoc bw negotiat.) */
-               if (!sd->jpeg_hdr)
-                       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-               if (!sd->jpeg_hdr)
-                       return -ENOMEM;
-
                jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
                            sd->gspca_dev.width, 0x22); /* JPEG 420 */
                jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -562,9 +553,6 @@ static void w9968cf_stop0(struct sd *sd)
                reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
                reg_w(sd, 0x16, 0x0000); /* stop video capture */
        }
-
-       kfree(sd->jpeg_hdr);
-       sd->jpeg_hdr = NULL;
 }
 
 /* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
index d02aa5c8472ad81d5b92b6fb0d510f0a64ba1d9b..4473f0fb8b73bb779ae88bcc160ffea77cc0346e 100644 (file)
@@ -22,7 +22,6 @@
 #define MODULE_NAME "zc3xx"
 
 #include <linux/input.h>
-#include <linux/slab.h>
 #include "gspca.h"
 #include "jpeg.h"
 
@@ -40,15 +39,16 @@ static int force_sensor = -1;
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
+       u8 brightness;
        u8 contrast;
        u8 gamma;
        u8 autogain;
        u8 lightfreq;
        u8 sharpness;
        u8 quality;                     /* image quality */
-#define QUALITY_MIN 40
-#define QUALITY_MAX 60
-#define QUALITY_DEF 50
+#define QUALITY_MIN 50
+#define QUALITY_MAX 80
+#define QUALITY_DEF 70
 
        u8 sensor;              /* Type of image sensor chip */
 /* !! values used in different tables */
@@ -75,10 +75,12 @@ struct sd {
 #define SENSOR_MAX 19
        unsigned short chip_revision;
 
-       u8 *jpeg_hdr;
+       u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* 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_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
@@ -91,6 +93,20 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static const struct ctrl sd_ctrls[] = {
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+#define BRIGHTNESS_DEF 128
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -132,7 +148,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
-#define LIGHTFREQ_IDX 3
+#define LIGHTFREQ_IDX 4
        {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -6011,9 +6027,12 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
        const u8 *Tgamma;
-       int g, i, k, adj, gp;
+       int g, i, brightness, contrast, adj, gp1, gp2;
        u8 gr[16];
-       static const u8 delta_tb[16] =          /* delta for contrast */
+       static const u8 delta_b[16] =           /* delta for brightness */
+               {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
+                0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18};
+       static const u8 delta_c[16] =           /* delta for contrast */
                {0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06,
                 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02};
        static const u8 gamma_tb[6][16] = {
@@ -6033,30 +6052,30 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 
        Tgamma = gamma_tb[sd->gamma - 1];
 
-       k = ((int) sd->contrast - 128);         /* -128 / 128 */
+       contrast = ((int) sd->contrast - 128);          /* -128 / 127 */
+       brightness = ((int) sd->brightness - 128);      /* -128 / 92 */
        adj = 0;
-       gp = 0;
+       gp1 = gp2 = 0;
        for (i = 0; i < 16; i++) {
-               g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2;
+               g = Tgamma[i] + delta_b[i] * brightness / 256
+                               - delta_c[i] * contrast / 256 - adj / 2;
                if (g > 0xff)
                        g = 0xff;
                else if (g < 0)
                        g = 0;
                reg_w(dev, g, 0x0120 + i);      /* gamma */
-               if (k > 0)
+               if (contrast > 0)
                        adj--;
-               else
+               else if (contrast < 0)
                        adj++;
-
-               if (i != 0) {
-                       if (gp == 0)
-                               gr[i - 1] = 0;
-                       else
-                               gr[i - 1] = g - gp;
-               }
-               gp = g;
+               if (i > 1)
+                       gr[i - 1] = (g - gp2) / 2;
+               else if (i != 0)
+                       gr[0] = gp1 == 0 ? 0 : (g - gp1);
+               gp2 = gp1;
+               gp1 = g;
        }
-       gr[15] = gr[14] / 2;
+       gr[15] = (0xff - gp2) / 2;
        for (i = 0; i < 16; i++)
                reg_w(dev, gr[i], 0x0130 + i);  /* gradient */
 }
@@ -6744,6 +6763,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = ARRAY_SIZE(broken_vga_mode);
                break;
        }
+       sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->gamma = gamma[sd->sensor];
        sd->autogain = AUTOGAIN_DEF;
@@ -6798,9 +6818,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        };
 
        /* create the JPEG header */
-       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-       if (!sd->jpeg_hdr)
-               return -ENOMEM;
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -6918,10 +6935,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(dev, 0x00, 0x0007);       /* (from win traces) */
                reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
                break;
-       case SENSOR_PAS202B:
-               reg_w(dev, 0x32, 0x0007);       /* (from win traces) */
-               reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
-               break;
        }
        return 0;
 }
@@ -6931,7 +6944,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       kfree(sd->jpeg_hdr);
        if (!gspca_dev->present)
                return;
        send_unknown(gspca_dev->dev, sd->sensor);
@@ -6962,6 +6974,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
+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)
+               setcontrast(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;
@@ -7163,9 +7193,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x046d, 0x08aa)},
        {USB_DEVICE(0x046d, 0x08ac)},
        {USB_DEVICE(0x046d, 0x08ad)},
-#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
        {USB_DEVICE(0x046d, 0x08ae)},
-#endif
        {USB_DEVICE(0x046d, 0x08af)},
        {USB_DEVICE(0x046d, 0x08b9)},
        {USB_DEVICE(0x046d, 0x08d7)},
index 830d47b05e1dba6f97520613e0299d217125cb67..0cae5b82e1a2e6eb84859dc4c49de40ef68ec5e3 100644 (file)
@@ -286,6 +286,8 @@ static int hdpvr_probe(struct usb_interface *interface,
                goto error;
        }
 
+       dev->workqueue = 0;
+
        /* register v4l2_device early so it can be used for printks */
        if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
                err("v4l2_device_register failed");
@@ -380,6 +382,9 @@ static int hdpvr_probe(struct usb_interface *interface,
 
 error:
        if (dev) {
+               /* Destroy single thread */
+               if (dev->workqueue)
+                       destroy_workqueue(dev->workqueue);
                /* this frees allocated memory */
                hdpvr_delete(dev);
        }
index c338f3f62e777abd0950d123c11338159a6788f0..4863a21b1f249963b949a304fc53666dbc394a50 100644 (file)
@@ -394,7 +394,7 @@ err:
 
 static int hdpvr_release(struct file *file)
 {
-       struct hdpvr_fh         *fh  = (struct hdpvr_fh *)file->private_data;
+       struct hdpvr_fh         *fh  = file->private_data;
        struct hdpvr_device     *dev = fh->dev;
 
        if (!dev)
@@ -518,7 +518,7 @@ err:
 static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 {
        struct hdpvr_buffer *buf = NULL;
-       struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+       struct hdpvr_fh *fh = filp->private_data;
        struct hdpvr_device *dev = fh->dev;
        unsigned int mask = 0;
 
index 29d439742653d0ab81006f575f47c6b29c31bab8..27ae8bbfb4777b4909afdd48e839c33359b39c93 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/i2c-id.h>
 #include <linux/workqueue.h>
 
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 #include <media/ir-kbd-i2c.h>
 
 /* ----------------------------------------------------------------------- */
@@ -272,11 +272,8 @@ static void ir_key_poll(struct IR_i2c *ir)
                return;
        }
 
-       if (0 == rc) {
-               ir_input_nokey(ir->input, &ir->ir);
-       } else {
-               ir_input_keydown(ir->input, &ir->ir, ir_key);
-       }
+       if (rc)
+               ir_keydown(ir->input, ir_key, 0);
 }
 
 static void ir_work(struct work_struct *work)
@@ -439,10 +436,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                 dev_name(&client->dev));
 
        /* init + register input device */
-       err = ir_input_init(input_dev, &ir->ir, ir_type);
-       if (err < 0)
-               goto err_out_free;
-
+       ir->ir_type = ir_type;
        input_dev->id.bustype = BUS_I2C;
        input_dev->name       = ir->name;
        input_dev->phys       = ir->phys;
index 1b79475ca134db7797c3ea95075a9fdfec61f983..90daa6e751d83dff10658368edb891ede0eaee81 100644 (file)
@@ -130,6 +130,9 @@ static int ivtv_yuv_threshold = -1;
 static int ivtv_pci_latency = 1;
 
 int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int ivtv_fw_debug;
+#endif
 
 static int tunertype = -1;
 static int newi2c = -1;
@@ -141,6 +144,9 @@ 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_named(debug,ivtv_debug, int, 0644);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
+#endif
 module_param(ivtv_pci_latency, int, 0644);
 module_param(ivtv_yuv_mode, int, 0644);
 module_param(ivtv_yuv_threshold, int, 0644);
@@ -217,6 +223,10 @@ MODULE_PARM_DESC(debug,
                 "\t\t\t 256/0x0100: yuv\n"
                 "\t\t\t 512/0x0200: i2c\n"
                 "\t\t\t1024/0x0400: high volume\n");
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+MODULE_PARM_DESC(fw_debug,
+                "Enable code for debugging firmware problems.  Default: 0\n");
+#endif
 MODULE_PARM_DESC(ivtv_pci_latency,
                 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
                 "\t\t\tDefault: Yes");
@@ -1425,12 +1435,16 @@ EXPORT_SYMBOL(ivtv_vapi);
 EXPORT_SYMBOL(ivtv_vapi_result);
 EXPORT_SYMBOL(ivtv_clear_irq_mask);
 EXPORT_SYMBOL(ivtv_debug);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+EXPORT_SYMBOL(ivtv_fw_debug);
+#endif
 EXPORT_SYMBOL(ivtv_reset_ir_gpio);
 EXPORT_SYMBOL(ivtv_udma_setup);
 EXPORT_SYMBOL(ivtv_udma_unmap);
 EXPORT_SYMBOL(ivtv_udma_alloc);
 EXPORT_SYMBOL(ivtv_udma_prepare);
 EXPORT_SYMBOL(ivtv_init_on_first_open);
+EXPORT_SYMBOL(ivtv_firmware_check);
 
 module_init(module_start);
 module_exit(module_cleanup);
index 5b45fd2b26458f8d5ad77e788e47a5d6bc48d851..bd084df4448ac0ccc81071373c0aeb48b9142762 100644 (file)
 
 /* debugging */
 extern int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+extern int ivtv_fw_debug;
+#endif
 
 #define IVTV_DBGFLG_WARN    (1 << 0)
 #define IVTV_DBGFLG_INFO    (1 << 1)
@@ -734,6 +737,7 @@ struct ivtv {
        struct v4l2_rect osd_rect;      /* current OSD position and size */
        struct v4l2_rect main_rect;     /* current Main window position and size */
        struct osd_info *osd_info;      /* ivtvfb private OSD info */
+       void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
 };
 
 static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
index 3c2cc270ccd548bd455b69073f3f584f6944650a..a6a2cdb81566f2aa6f68b614fedb8aea54f976af 100644 (file)
@@ -32,6 +32,7 @@
 #include "ivtv-yuv.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-cards.h"
+#include "ivtv-firmware.h"
 #include <media/v4l2-event.h>
 #include <media/saa7115.h>
 
@@ -526,6 +527,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
 {
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
+       int rc;
 
        if (atomic_read(&itv->decoding) == 0) {
                if (ivtv_claim_stream(id, s->type)) {
@@ -533,7 +535,13 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
                        IVTV_DEBUG_WARN("start decode, stream already claimed\n");
                        return -EBUSY;
                }
-               ivtv_start_v4l2_decode_stream(s, 0);
+               rc = ivtv_start_v4l2_decode_stream(s, 0);
+               if (rc < 0) {
+                       if (rc == -EAGAIN)
+                               rc = ivtv_start_v4l2_decode_stream(s, 0);
+                       if (rc < 0)
+                               return rc;
+               }
        }
        if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
                return ivtv_set_speed(itv, speed);
@@ -912,12 +920,32 @@ int ivtv_v4l2_close(struct file *filp)
 
 static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       struct video_device *vdev = video_devdata(filp);
+#endif
        struct ivtv *itv = s->itv;
        struct ivtv_open_id *item;
        int res = 0;
 
        IVTV_DEBUG_FILE("open %s\n", s->name);
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       /* Unless ivtv_fw_debug is set, error out if firmware dead. */
+       if (ivtv_fw_debug) {
+               IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
+                         video_device_node_name(vdev));
+               IVTV_WARN("Selected firmware errors will be ignored\n");
+       } else {
+#else
+       if (1) {
+#endif
+               res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+               if (res == -EAGAIN)
+                       res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+               if (res < 0)
+                       return -EIO;
+       }
+
        if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
                test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
                return -EBUSY;
index a71e8ba306b0c97626865243bb09c316bea0a496..d8bf2b01729dc9a8bcdcfc20e63480990b4a4729 100644 (file)
 #include "ivtv-mailbox.h"
 #include "ivtv-firmware.h"
 #include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
 #include <linux/firmware.h>
+#include <media/saa7127.h>
 
 #define IVTV_MASK_SPU_ENABLE           0xFFFFFFFE
 #define IVTV_MASK_VPU_ENABLE15                 0xFFFFFFF6
@@ -271,3 +274,122 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
        }
        ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
 }
+
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+       int rc = 0;
+       v4l2_std_id std;
+       struct ivtv_open_id fh;
+       fh.itv = itv;
+
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+               /* Display test image during restart */
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+                   SAA7127_INPUT_TYPE_TEST_IMAGE,
+                   itv->card->video_outputs[itv->active_output].video_output,
+                   0);
+
+       mutex_lock(&itv->udma.lock);
+
+       rc = ivtv_firmware_init(itv);
+       if (rc) {
+               mutex_unlock(&itv->udma.lock);
+               return rc;
+       }
+
+       /* Allow settings to reload */
+       ivtv_mailbox_cache_invalidate(itv);
+
+       /* Restore video standard */
+       std = itv->std;
+       itv->std = 0;
+       ivtv_s_std(NULL, &fh, &std);
+
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+               ivtv_init_mpeg_decoder(itv);
+
+               /* Restore framebuffer if active */
+               if (itv->ivtvfb_restore)
+                       itv->ivtvfb_restore(itv);
+
+               /* Restore alpha settings */
+               ivtv_set_osd_alpha(itv);
+
+               /* Restore normal output */
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+                   SAA7127_INPUT_TYPE_NORMAL,
+                   itv->card->video_outputs[itv->active_output].video_output,
+                   0);
+       }
+
+       mutex_unlock(&itv->udma.lock);
+       return rc;
+}
+
+/* Check firmware running state. The checks fall through
+   allowing multiple failures to be logged. */
+int ivtv_firmware_check(struct ivtv *itv, char *where)
+{
+       int res = 0;
+
+       /* Check encoder is still running */
+       if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
+               IVTV_WARN("Encoder has died : %s\n", where);
+               res = -1;
+       }
+
+       /* Also check audio. Only check if not in use & encoder is okay */
+       if (!res && !atomic_read(&itv->capturing) &&
+           (!atomic_read(&itv->decoding) ||
+            (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
+                                                            &itv->i_flags)))) {
+
+               if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
+                       IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
+                       res = -2;
+               }
+       }
+
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+               /* Second audio check. Skip if audio already failed */
+               if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
+                       /* Wait & try again to be certain. */
+                       ivtv_msleep_timeout(14, 0);
+                       if (read_dec(0x100) != read_dec(0x104)) {
+                               IVTV_WARN("Audio has died (Decoder) : %s\n",
+                                         where);
+                               res = -1;
+                       }
+               }
+
+               /* Check decoder is still running */
+               if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
+                       IVTV_WARN("Decoder has died : %s\n", where);
+                       res = -1;
+               }
+       }
+
+       /* If something failed & currently idle, try to reload */
+       if (res && !atomic_read(&itv->capturing) &&
+                                               !atomic_read(&itv->decoding)) {
+               IVTV_INFO("Detected in %s that firmware had failed - "
+                         "Reloading\n", where);
+               res = ivtv_firmware_restart(itv);
+               /*
+                * Even if restarted ok, still signal a problem had occured.
+                * The caller can come through this function again to check
+                * if things are really ok after the restart.
+                */
+               if (!res) {
+                       IVTV_INFO("Firmware restart okay\n");
+                       res = -EAGAIN;
+               } else {
+                       IVTV_INFO("Firmware restart failed\n");
+               }
+       } else if (res) {
+               res = -EIO;
+       }
+
+       return res;
+}
index 041ba94e65bc46aad55d007f6632ea34444ae85e..52bb4e5598fd398e2af2dc6397e1d7e68720147b 100644 (file)
@@ -26,5 +26,6 @@ int ivtv_firmware_init(struct ivtv *itv);
 void ivtv_firmware_versions(struct ivtv *itv);
 void ivtv_halt_firmware(struct ivtv *itv);
 void ivtv_init_mpeg_decoder(struct ivtv *itv);
+int ivtv_firmware_check(struct ivtv *itv, char *where);
 
 #endif
index 84577f6f41a24dd8f35956d041d2f0487f09af1e..e3ce967637853d906756009cce321c930c2f82c9 100644 (file)
@@ -377,3 +377,11 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
        for (i = 0; i < argc; i++, p++)
                data[i] = readl(p);
 }
+
+/* Wipe api cache */
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
+{
+       int i;
+       for (i = 0; i < 256; i++)
+               itv->api_cache[i].last_jiffies = 0;
+}
index 8247662c928ed916e4e8f2e015f4651e55f1d1a3..2c834d2cb56f2b233a1e610fc7cb4153c17dcabb 100644 (file)
@@ -30,5 +30,6 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
 int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
 int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
 int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv);
 
 #endif
index a937e2ff9b6ebcad8a8d5e3e5025c140d34ccef3..55df4190c28d03e7b32459b359de0c302ee7570b 100644 (file)
@@ -42,6 +42,7 @@
 #include "ivtv-yuv.h"
 #include "ivtv-cards.h"
 #include "ivtv-streams.h"
+#include "ivtv-firmware.h"
 #include <media/v4l2-event.h>
 
 static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
@@ -674,12 +675,14 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
        /* Decoder sometimes dies here, so wait a moment */
        ivtv_msleep_timeout(10, 0);
 
-       return 0;
+       /* Known failure point for firmware, so check */
+       return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
 }
 
 int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
 {
        struct ivtv *itv = s->itv;
+       int rc;
 
        if (s->vdev == NULL)
                return -EINVAL;
@@ -689,7 +692,11 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
 
        IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
 
-       ivtv_setup_v4l2_decode_stream(s);
+       rc = ivtv_setup_v4l2_decode_stream(s);
+       if (rc < 0) {
+               clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+               return rc;
+       }
 
        /* set dma size to 65536 bytes */
        ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
index b530dec399d31dda6aa24ee1d7864ed855832bf9..b67a4048f5aa422fe7c198ae467c58fdd6c3b964 100644 (file)
@@ -23,7 +23,7 @@
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
 #define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 2
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
 #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
index 9ff3425891edc7f678452317d33351ab80a4034c..be03a712731c3b61a249d607927fb852f0517881 100644 (file)
@@ -53,6 +53,7 @@
 #include "ivtv-i2c.h"
 #include "ivtv-udma.h"
 #include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
 
 /* card parameters */
 static int ivtvfb_card_id = -1;
@@ -178,6 +179,12 @@ struct osd_info {
        struct fb_info ivtvfb_info;
        struct fb_var_screeninfo ivtvfb_defined;
        struct fb_fix_screeninfo ivtvfb_fix;
+
+       /* Used for a warm start */
+       struct fb_var_screeninfo fbvar_cur;
+       int blank_cur;
+       u32 palette_cur[256];
+       u32 pan_cur;
 };
 
 struct ivtv_osd_coords {
@@ -199,6 +206,7 @@ static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
        u32 data[CX2341X_MBOX_MAX_DATA];
        int rc;
 
+       ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
        rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
        *fbbase = data[0];
        *fblength = data[1];
@@ -581,8 +589,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
        ivtv_window.height = var->yres;
 
        /* Minimum margin cannot be 0, as X won't allow such a mode */
-       if (!var->upper_margin) var->upper_margin++;
-       if (!var->left_margin) var->left_margin++;
+       if (!var->upper_margin)
+               var->upper_margin++;
+       if (!var->left_margin)
+               var->left_margin++;
        ivtv_window.top = var->upper_margin - 1;
        ivtv_window.left = var->left_margin - 1;
 
@@ -595,6 +605,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
        /* Force update of yuv registers */
        itv->yuv_info.yuv_forced_update = 1;
 
+       /* Keep a copy of these settings */
+       memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
+
        IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
                      var->xres, var->yres,
                      var->xres_virtual, var->yres_virtual,
@@ -829,6 +842,8 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf
        itv->yuv_info.osd_y_pan = var->yoffset;
        /* Force update of yuv registers */
        itv->yuv_info.yuv_forced_update = 1;
+       /* Remember this value */
+       itv->osd_info->pan_cur = osd_pan_index;
        return 0;
 }
 
@@ -842,6 +857,7 @@ static int ivtvfb_set_par(struct fb_info *info)
        rc = ivtvfb_set_var(itv, &info->var);
        ivtvfb_pan_display(&info->var, info);
        ivtvfb_get_fix(itv, &info->fix);
+       ivtv_firmware_check(itv, "ivtvfb_set_par");
        return rc;
 }
 
@@ -859,6 +875,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
        if (info->var.bits_per_pixel <= 8) {
                write_reg(regno, 0x02a30);
                write_reg(color, 0x02a34);
+               itv->osd_info->palette_cur[regno] = color;
                return 0;
        }
        if (regno >= 16)
@@ -911,6 +928,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
                ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
                break;
        }
+       itv->osd_info->blank_cur = blank_mode;
        return 0;
 }
 
@@ -929,6 +947,21 @@ static struct fb_ops ivtvfb_ops = {
        .fb_blank       = ivtvfb_blank,
 };
 
+/* Restore hardware after firmware restart */
+static void ivtvfb_restore(struct ivtv *itv)
+{
+       struct osd_info *oi = itv->osd_info;
+       int i;
+
+       ivtvfb_set_var(itv, &oi->fbvar_cur);
+       ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
+       for (i = 0; i < 256; i++) {
+               write_reg(i, 0x02a30);
+               write_reg(oi->palette_cur[i], 0x02a34);
+       }
+       write_reg(oi->pan_cur, 0x02a0c);
+}
+
 /* Initialization */
 
 
@@ -1192,6 +1225,9 @@ static int ivtvfb_init_card(struct ivtv *itv)
        /* Enable the osd */
        ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
 
+       /* Enable restart */
+       itv->ivtvfb_restore = ivtvfb_restore;
+
        /* Allocate DMA */
        ivtv_udma_alloc(itv);
        return 0;
@@ -1203,7 +1239,7 @@ static int __init ivtvfb_callback_init(struct device *dev, void *p)
        struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
        struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
 
-       if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
                if (ivtvfb_init_card(itv) == 0) {
                        IVTVFB_INFO("Framebuffer registered on %s\n",
                                        itv->v4l2_dev.name);
@@ -1219,13 +1255,14 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
        struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
        struct osd_info *oi = itv->osd_info;
 
-       if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+       if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
                if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
                        IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
                                       itv->instance);
                        return 0;
                }
                IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+               itv->ivtvfb_restore = NULL;
                ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
                ivtvfb_release_buffers(itv);
                itv->osd_video_pbase = 0;
index 10ddeccc70ebee17045ad57cd4f8af1248223b00..4525335f9bd416388484cbc5872ea0db3c3af768 100644 (file)
@@ -903,14 +903,14 @@ static int m2mtest_release(struct file *file)
 static unsigned int m2mtest_poll(struct file *file,
                                 struct poll_table_struct *wait)
 {
-       struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+       struct m2mtest_ctx *ctx = file->private_data;
 
        return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 }
 
 static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+       struct m2mtest_ctx *ctx = file->private_data;
 
        return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 }
index fbd0fc794720cb21ef56345315a382d0f3263e27..31cc3d04bcc49b18465511faa4d910c192298497 100644 (file)
@@ -143,10 +143,10 @@ static const struct mt9m111_datafmt *mt9m111_find_datafmt(
 }
 
 static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
-       {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
-       {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
-       {V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG},
-       {V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
@@ -505,22 +505,22 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
        case V4L2_MBUS_FMT_RGB565_2X8_LE:
                ret = mt9m111_setfmt_rgb565(client);
                break;
-       case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
                mt9m111->swap_yuv_y_chromas = 0;
                mt9m111->swap_yuv_cb_cr = 0;
                ret = mt9m111_setfmt_yuv(client);
                break;
-       case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
                mt9m111->swap_yuv_y_chromas = 0;
                mt9m111->swap_yuv_cb_cr = 1;
                ret = mt9m111_setfmt_yuv(client);
                break;
-       case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
                mt9m111->swap_yuv_y_chromas = 1;
                mt9m111->swap_yuv_cb_cr = 0;
                ret = mt9m111_setfmt_yuv(client);
                break;
-       case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
                mt9m111->swap_yuv_y_chromas = 1;
                mt9m111->swap_yuv_cb_cr = 1;
                ret = mt9m111_setfmt_yuv(client);
index e4bf1db9a87b4d978eaad6646c1fed2b1076cf70..8ec47e42d4d0d7e630f114e1dc85eb1c0d415cf8 100644 (file)
@@ -121,22 +121,22 @@ struct mt9t112_priv {
 
 static const struct mt9t112_format mt9t112_cfmts[] = {
        {
-               .code           = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+               .code           = V4L2_MBUS_FMT_UYVY8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .fmt            = 1,
                .order          = 0,
        }, {
-               .code           = V4L2_MBUS_FMT_YVYU8_2X8_BE,
+               .code           = V4L2_MBUS_FMT_VYUY8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .fmt            = 1,
                .order          = 1,
        }, {
-               .code           = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+               .code           = V4L2_MBUS_FMT_YUYV8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .fmt            = 1,
                .order          = 2,
        }, {
-               .code           = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+               .code           = V4L2_MBUS_FMT_YVYU8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .fmt            = 1,
                .order          = 3,
@@ -972,7 +972,7 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
        struct v4l2_rect *rect = &a->c;
 
        return mt9t112_set_params(client, rect->width, rect->height,
-                                V4L2_MBUS_FMT_YUYV8_2X8_BE);
+                                V4L2_MBUS_FMT_UYVY8_2X8);
 }
 
 static int mt9t112_g_fmt(struct v4l2_subdev *sd,
@@ -983,7 +983,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,
 
        if (!priv->format) {
                int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
-                                            V4L2_MBUS_FMT_YUYV8_2X8_BE);
+                                            V4L2_MBUS_FMT_UYVY8_2X8);
                if (ret < 0)
                        return ret;
        }
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
new file mode 100644 (file)
index 0000000..026bef0
--- /dev/null
@@ -0,0 +1,1513 @@
+/*
+ * V4L2 Driver for i.MX27/i.MX25 camera host
+ *
+ * Copyright (C) 2008, Sascha Hauer, Pengutronix
+ * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#include <linux/videodev2.h>
+
+#include <mach/mx2_cam.h>
+#ifdef CONFIG_MACH_MX27
+#include <mach/dma-mx1-mx2.h>
+#endif
+#include <mach/hardware.h>
+
+#include <asm/dma.h>
+
+#define MX2_CAM_DRV_NAME "mx2-camera"
+#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
+
+/* reset values */
+#define CSICR1_RESET_VAL       0x40000800
+#define CSICR2_RESET_VAL       0x0
+#define CSICR3_RESET_VAL       0x0
+
+/* csi control reg 1 */
+#define CSICR1_SWAP16_EN       (1 << 31)
+#define CSICR1_EXT_VSYNC       (1 << 30)
+#define CSICR1_EOF_INTEN       (1 << 29)
+#define CSICR1_PRP_IF_EN       (1 << 28)
+#define CSICR1_CCIR_MODE       (1 << 27)
+#define CSICR1_COF_INTEN       (1 << 26)
+#define CSICR1_SF_OR_INTEN     (1 << 25)
+#define CSICR1_RF_OR_INTEN     (1 << 24)
+#define CSICR1_STATFF_LEVEL    (3 << 22)
+#define CSICR1_STATFF_INTEN    (1 << 21)
+#define CSICR1_RXFF_LEVEL(l)   (((l) & 3) << 19)       /* MX27 */
+#define CSICR1_FB2_DMA_INTEN   (1 << 20)               /* MX25 */
+#define CSICR1_FB1_DMA_INTEN   (1 << 19)               /* MX25 */
+#define CSICR1_RXFF_INTEN      (1 << 18)
+#define CSICR1_SOF_POL         (1 << 17)
+#define CSICR1_SOF_INTEN       (1 << 16)
+#define CSICR1_MCLKDIV(d)      (((d) & 0xF) << 12)
+#define CSICR1_HSYNC_POL       (1 << 11)
+#define CSICR1_CCIR_EN         (1 << 10)
+#define CSICR1_MCLKEN          (1 << 9)
+#define CSICR1_FCC             (1 << 8)
+#define CSICR1_PACK_DIR                (1 << 7)
+#define CSICR1_CLR_STATFIFO    (1 << 6)
+#define CSICR1_CLR_RXFIFO      (1 << 5)
+#define CSICR1_GCLK_MODE       (1 << 4)
+#define CSICR1_INV_DATA                (1 << 3)
+#define CSICR1_INV_PCLK                (1 << 2)
+#define CSICR1_REDGE           (1 << 1)
+
+#define SHIFT_STATFF_LEVEL     22
+#define SHIFT_RXFF_LEVEL       19
+#define SHIFT_MCLKDIV          12
+
+/* control reg 3 */
+#define CSICR3_FRMCNT          (0xFFFF << 16)
+#define CSICR3_FRMCNT_RST      (1 << 15)
+#define CSICR3_DMA_REFLASH_RFF (1 << 14)
+#define CSICR3_DMA_REFLASH_SFF (1 << 13)
+#define CSICR3_DMA_REQ_EN_RFF  (1 << 12)
+#define CSICR3_DMA_REQ_EN_SFF  (1 << 11)
+#define CSICR3_RXFF_LEVEL(l)   (((l) & 7) << 4)        /* MX25 */
+#define CSICR3_CSI_SUP         (1 << 3)
+#define CSICR3_ZERO_PACK_EN    (1 << 2)
+#define CSICR3_ECC_INT_EN      (1 << 1)
+#define CSICR3_ECC_AUTO_EN     (1 << 0)
+
+#define SHIFT_FRMCNT           16
+
+/* csi status reg */
+#define CSISR_SFF_OR_INT       (1 << 25)
+#define CSISR_RFF_OR_INT       (1 << 24)
+#define CSISR_STATFF_INT       (1 << 21)
+#define CSISR_DMA_TSF_FB2_INT  (1 << 20)       /* MX25 */
+#define CSISR_DMA_TSF_FB1_INT  (1 << 19)       /* MX25 */
+#define CSISR_RXFF_INT         (1 << 18)
+#define CSISR_EOF_INT          (1 << 17)
+#define CSISR_SOF_INT          (1 << 16)
+#define CSISR_F2_INT           (1 << 15)
+#define CSISR_F1_INT           (1 << 14)
+#define CSISR_COF_INT          (1 << 13)
+#define CSISR_ECC_INT          (1 << 1)
+#define CSISR_DRDY             (1 << 0)
+
+#define CSICR1                 0x00
+#define CSICR2                 0x04
+#define CSISR                  (cpu_is_mx27() ? 0x08 : 0x18)
+#define CSISTATFIFO            0x0c
+#define CSIRFIFO               0x10
+#define CSIRXCNT               0x14
+#define CSICR3                 (cpu_is_mx27() ? 0x1C : 0x08)
+#define CSIDMASA_STATFIFO      0x20
+#define CSIDMATA_STATFIFO      0x24
+#define CSIDMASA_FB1           0x28
+#define CSIDMASA_FB2           0x2c
+#define CSIFBUF_PARA           0x30
+#define CSIIMAG_PARA           0x34
+
+/* EMMA PrP */
+#define PRP_CNTL                       0x00
+#define PRP_INTR_CNTL                  0x04
+#define PRP_INTRSTATUS                 0x08
+#define PRP_SOURCE_Y_PTR               0x0c
+#define PRP_SOURCE_CB_PTR              0x10
+#define PRP_SOURCE_CR_PTR              0x14
+#define PRP_DEST_RGB1_PTR              0x18
+#define PRP_DEST_RGB2_PTR              0x1c
+#define PRP_DEST_Y_PTR                 0x20
+#define PRP_DEST_CB_PTR                        0x24
+#define PRP_DEST_CR_PTR                        0x28
+#define PRP_SRC_FRAME_SIZE             0x2c
+#define PRP_DEST_CH1_LINE_STRIDE       0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL      0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL      0x38
+#define PRP_CH1_OUT_IMAGE_SIZE         0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE         0x40
+#define PRP_SRC_LINE_STRIDE            0x44
+#define PRP_CSC_COEF_012               0x48
+#define PRP_CSC_COEF_345               0x4c
+#define PRP_CSC_COEF_678               0x50
+#define PRP_CH1_RZ_HORI_COEF1          0x54
+#define PRP_CH1_RZ_HORI_COEF2          0x58
+#define PRP_CH1_RZ_HORI_VALID          0x5c
+#define PRP_CH1_RZ_VERT_COEF1          0x60
+#define PRP_CH1_RZ_VERT_COEF2          0x64
+#define PRP_CH1_RZ_VERT_VALID          0x68
+#define PRP_CH2_RZ_HORI_COEF1          0x6c
+#define PRP_CH2_RZ_HORI_COEF2          0x70
+#define PRP_CH2_RZ_HORI_VALID          0x74
+#define PRP_CH2_RZ_VERT_COEF1          0x78
+#define PRP_CH2_RZ_VERT_COEF2          0x7c
+#define PRP_CH2_RZ_VERT_VALID          0x80
+
+#define PRP_CNTL_CH1EN         (1 << 0)
+#define PRP_CNTL_CH2EN         (1 << 1)
+#define PRP_CNTL_CSIEN         (1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420        (0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422        (1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16 (2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32 (3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8  (0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422        (3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420        (0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444        (2 << 7)
+#define PRP_CNTL_CH1_LEN       (1 << 9)
+#define PRP_CNTL_CH2_LEN       (1 << 10)
+#define PRP_CNTL_SKIP_FRAME    (1 << 11)
+#define PRP_CNTL_SWRST         (1 << 12)
+#define PRP_CNTL_CLKEN         (1 << 13)
+#define PRP_CNTL_WEN           (1 << 14)
+#define PRP_CNTL_CH1BYP                (1 << 15)
+#define PRP_CNTL_IN_TSKIP(x)   ((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x)  ((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x)  ((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x)   ((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x)      ((x) << 27)
+#define PRP_CNTL_CH2B1EN       (1 << 29)
+#define PRP_CNTL_CH2B2EN       (1 << 30)
+#define PRP_CNTL_CH2FEN                (1 << 31)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR         (1 << 0)
+#define PRP_INTR_CH1WERR       (1 << 1)
+#define PRP_INTR_CH2WERR       (1 << 2)
+#define PRP_INTR_CH1FC         (1 << 3)
+#define PRP_INTR_CH2FC         (1 << 5)
+#define PRP_INTR_LBOVF         (1 << 7)
+#define PRP_INTR_CH2OVF                (1 << 8)
+
+#define mx27_camera_emma(pcdev)        (cpu_is_mx27() && pcdev->use_emma)
+
+#define MAX_VIDEO_MEM  16
+
+struct mx2_camera_dev {
+       struct device           *dev;
+       struct soc_camera_host  soc_host;
+       struct soc_camera_device *icd;
+       struct clk              *clk_csi, *clk_emma;
+
+       unsigned int            irq_csi, irq_emma;
+       void __iomem            *base_csi, *base_emma;
+       unsigned long           base_dma;
+
+       struct mx2_camera_platform_data *pdata;
+       struct resource         *res_csi, *res_emma;
+       unsigned long           platform_flags;
+
+       struct list_head        capture;
+       struct list_head        active_bufs;
+
+       spinlock_t              lock;
+
+       int                     dma;
+       struct mx2_buffer       *active;
+       struct mx2_buffer       *fb1_active;
+       struct mx2_buffer       *fb2_active;
+
+       int                     use_emma;
+
+       u32                     csicr1;
+
+       void                    *discard_buffer;
+       dma_addr_t              discard_buffer_dma;
+       size_t                  discard_size;
+};
+
+/* buffer for one video frame */
+struct mx2_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer          vb;
+
+       enum v4l2_mbus_pixelcode        code;
+
+       int bufnum;
+};
+
+static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
+{
+       unsigned long flags;
+
+       clk_disable(pcdev->clk_csi);
+       writel(0, pcdev->base_csi + CSICR1);
+       if (mx27_camera_emma(pcdev)) {
+               writel(0, pcdev->base_emma + PRP_CNTL);
+       } else if (cpu_is_mx25()) {
+               spin_lock_irqsave(&pcdev->lock, flags);
+               pcdev->fb1_active = NULL;
+               pcdev->fb2_active = NULL;
+               writel(0, pcdev->base_csi + CSIDMASA_FB1);
+               writel(0, pcdev->base_csi + CSIDMASA_FB2);
+               spin_unlock_irqrestore(&pcdev->lock, flags);
+       }
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on mx2 camera sensor interface
+ */
+static int mx2_camera_add_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       int ret;
+       u32 csicr1;
+
+       if (pcdev->icd)
+               return -EBUSY;
+
+       ret = clk_enable(pcdev->clk_csi);
+       if (ret < 0)
+               return ret;
+
+       csicr1 = CSICR1_MCLKEN;
+
+       if (mx27_camera_emma(pcdev)) {
+               csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
+                       CSICR1_RXFF_LEVEL(0);
+       } else if (cpu_is_mx27())
+               csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
+
+       pcdev->csicr1 = csicr1;
+       writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+       pcdev->icd = icd;
+
+       dev_info(icd->dev.parent, "Camera driver attached to camera %d\n",
+                icd->devnum);
+
+       return 0;
+}
+
+static void mx2_camera_remove_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+
+       BUG_ON(icd != pcdev->icd);
+
+       dev_info(icd->dev.parent, "Camera driver detached from camera %d\n",
+                icd->devnum);
+
+       mx2_camera_deactivate(pcdev);
+
+       if (pcdev->discard_buffer) {
+               dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size,
+                               pcdev->discard_buffer,
+                               pcdev->discard_buffer_dma);
+               pcdev->discard_buffer = NULL;
+       }
+
+       pcdev->icd = NULL;
+}
+
+#ifdef CONFIG_MACH_MX27
+static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev)
+{
+       u32 tmp;
+
+       imx_dma_enable(pcdev->dma);
+
+       tmp = readl(pcdev->base_csi + CSICR1);
+       tmp |= CSICR1_RF_OR_INTEN;
+       writel(tmp, pcdev->base_csi + CSICR1);
+}
+
+static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
+{
+       struct mx2_camera_dev *pcdev = data;
+       u32 status = readl(pcdev->base_csi + CSISR);
+
+       if (status & CSISR_SOF_INT && pcdev->active) {
+               u32 tmp;
+
+               tmp = readl(pcdev->base_csi + CSICR1);
+               writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1);
+               mx27_camera_dma_enable(pcdev);
+       }
+
+       writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
+
+       return IRQ_HANDLED;
+}
+#else
+static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
+{
+       return IRQ_NONE;
+}
+#endif /* CONFIG_MACH_MX27 */
+
+static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
+               int state)
+{
+       struct videobuf_buffer *vb;
+       struct mx2_buffer *buf;
+       struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
+               &pcdev->fb2_active;
+       u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pcdev->lock, flags);
+
+       vb = &(*fb_active)->vb;
+       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       vb->state = state;
+       do_gettimeofday(&vb->ts);
+       vb->field_count++;
+
+       wake_up(&vb->done);
+
+       if (list_empty(&pcdev->capture)) {
+               buf = NULL;
+               writel(0, pcdev->base_csi + fb_reg);
+       } else {
+               buf = list_entry(pcdev->capture.next, struct mx2_buffer,
+                               vb.queue);
+               vb = &buf->vb;
+               list_del(&vb->queue);
+               vb->state = VIDEOBUF_ACTIVE;
+               writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
+       }
+
+       *fb_active = buf;
+
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
+{
+       struct mx2_camera_dev *pcdev = data;
+       u32 status = readl(pcdev->base_csi + CSISR);
+
+       if (status & CSISR_DMA_TSF_FB1_INT)
+               mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
+       else if (status & CSISR_DMA_TSF_FB2_INT)
+               mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
+
+       /* FIXME: handle CSISR_RFF_OR_INT */
+
+       writel(status, pcdev->base_csi + CSISR);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ *  Videobuf operations
+ */
+static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+                             unsigned int *size)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                       icd->current_fmt->host_fmt);
+
+       dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       *size = bytes_per_line * icd->user_height;
+
+       if (0 == *count)
+               *count = 32;
+       if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+               *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+       return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct videobuf_buffer *vb = &buf->vb;
+
+       dev_dbg(&icd->dev, "%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(vb, 0, 0);
+
+       videobuf_dma_contig_free(vq, vb);
+       dev_dbg(&icd->dev, "%s freed\n", __func__);
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int mx2_videobuf_prepare(struct videobuf_queue *vq,
+               struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+       int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                       icd->current_fmt->host_fmt);
+       int ret = 0;
+
+       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+#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);
+#endif
+
+       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;
+       }
+
+       vb->size = bytes_per_line * vb->height;
+       if (vb->baddr && vb->bsize < vb->size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               ret = videobuf_iolock(vq, vb, NULL);
+               if (ret)
+                       goto fail;
+
+               vb->state = VIDEOBUF_PREPARED;
+       }
+
+       return 0;
+
+fail:
+       free_buffer(vq, buf);
+out:
+       return ret;
+}
+
+static void mx2_videobuf_queue(struct videobuf_queue *vq,
+                              struct videobuf_buffer *vb)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+       unsigned long flags;
+
+       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       spin_lock_irqsave(&pcdev->lock, flags);
+
+       vb->state = VIDEOBUF_QUEUED;
+       list_add_tail(&vb->queue, &pcdev->capture);
+
+       if (mx27_camera_emma(pcdev)) {
+               goto out;
+#ifdef CONFIG_MACH_MX27
+       } else if (cpu_is_mx27()) {
+               int ret;
+
+               if (pcdev->active == NULL) {
+                       ret = imx_dma_setup_single(pcdev->dma,
+                                       videobuf_to_dma_contig(vb), vb->size,
+                                       (u32)pcdev->base_dma + 0x10,
+                                       DMA_MODE_READ);
+                       if (ret) {
+                               vb->state = VIDEOBUF_ERROR;
+                               wake_up(&vb->done);
+                               goto out;
+                       }
+
+                       vb->state = VIDEOBUF_ACTIVE;
+                       pcdev->active = buf;
+               }
+#endif
+       } else { /* cpu_is_mx25() */
+               u32 csicr3, dma_inten = 0;
+
+               if (pcdev->fb1_active == NULL) {
+                       writel(videobuf_to_dma_contig(vb),
+                                       pcdev->base_csi + CSIDMASA_FB1);
+                       pcdev->fb1_active = buf;
+                       dma_inten = CSICR1_FB1_DMA_INTEN;
+               } else if (pcdev->fb2_active == NULL) {
+                       writel(videobuf_to_dma_contig(vb),
+                                       pcdev->base_csi + CSIDMASA_FB2);
+                       pcdev->fb2_active = buf;
+                       dma_inten = CSICR1_FB2_DMA_INTEN;
+               }
+
+               if (dma_inten) {
+                       list_del(&vb->queue);
+                       vb->state = VIDEOBUF_ACTIVE;
+
+                       csicr3 = readl(pcdev->base_csi + CSICR3);
+
+                       /* Reflash DMA */
+                       writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
+                                       pcdev->base_csi + CSICR3);
+
+                       /* clear & enable interrupts */
+                       writel(dma_inten, pcdev->base_csi + CSISR);
+                       pcdev->csicr1 |= dma_inten;
+                       writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+                       /* enable DMA */
+                       csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
+                       writel(csicr3, pcdev->base_csi + CSICR3);
+               }
+       }
+
+out:
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx2_videobuf_release(struct videobuf_queue *vq,
+                                struct videobuf_buffer *vb)
+{
+       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+       unsigned long flags;
+
+#ifdef DEBUG
+       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       switch (vb->state) {
+       case VIDEOBUF_ACTIVE:
+               dev_info(&icd->dev, "%s (active)\n", __func__);
+               break;
+       case VIDEOBUF_QUEUED:
+               dev_info(&icd->dev, "%s (queued)\n", __func__);
+               break;
+       case VIDEOBUF_PREPARED:
+               dev_info(&icd->dev, "%s (prepared)\n", __func__);
+               break;
+       default:
+               dev_info(&icd->dev, "%s (unknown) %d\n", __func__,
+                               vb->state);
+               break;
+       }
+#endif
+
+       /*
+        * Terminate only queued but inactive buffers. Active buffers are
+        * released when they become inactive after videobuf_waiton().
+        *
+        * FIXME: implement forced termination of active buffers, so that the
+        * user won't get stuck in an uninterruptible state. This requires a
+        * specific handling for each of the three DMA types that this driver
+        * supports.
+        */
+       spin_lock_irqsave(&pcdev->lock, flags);
+       if (vb->state == VIDEOBUF_QUEUED) {
+               list_del(&vb->queue);
+               vb->state = VIDEOBUF_ERROR;
+       }
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops mx2_videobuf_ops = {
+       .buf_setup      = mx2_videobuf_setup,
+       .buf_prepare    = mx2_videobuf_prepare,
+       .buf_queue      = mx2_videobuf_queue,
+       .buf_release    = mx2_videobuf_release,
+};
+
+static void mx2_camera_init_videobuf(struct videobuf_queue *q,
+                             struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+
+       videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
+                       &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                       V4L2_FIELD_NONE, sizeof(struct mx2_buffer), icd);
+}
+
+#define MX2_BUS_FLAGS  (SOCAM_DATAWIDTH_8 | \
+                       SOCAM_MASTER | \
+                       SOCAM_VSYNC_ACTIVE_HIGH | \
+                       SOCAM_VSYNC_ACTIVE_LOW | \
+                       SOCAM_HSYNC_ACTIVE_HIGH | \
+                       SOCAM_HSYNC_ACTIVE_LOW | \
+                       SOCAM_PCLK_SAMPLE_RISING | \
+                       SOCAM_PCLK_SAMPLE_FALLING | \
+                       SOCAM_DATA_ACTIVE_HIGH | \
+                       SOCAM_DATA_ACTIVE_LOW)
+
+static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
+{
+       u32 cntl;
+       int count = 0;
+
+       cntl = readl(pcdev->base_emma + PRP_CNTL);
+       writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+       while (count++ < 100) {
+               if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
+                       return 0;
+               barrier();
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
+               int bytesperline)
+{
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+
+       writel(pcdev->discard_buffer_dma,
+                       pcdev->base_emma + PRP_DEST_RGB1_PTR);
+       writel(pcdev->discard_buffer_dma,
+                       pcdev->base_emma + PRP_DEST_RGB2_PTR);
+
+       /*
+        * We only use the EMMA engine to get rid of the broken
+        * DMA Engine. No color space consversion at the moment.
+        * We adjust incoming and outgoing pixelformat to rgb16
+        * and adjust the bytesperline accordingly.
+        */
+       writel(PRP_CNTL_CH1EN |
+                       PRP_CNTL_CSIEN |
+                       PRP_CNTL_DATA_IN_RGB16 |
+                       PRP_CNTL_CH1_OUT_RGB16 |
+                       PRP_CNTL_CH1_LEN |
+                       PRP_CNTL_CH1BYP |
+                       PRP_CNTL_CH1_TSKIP(0) |
+                       PRP_CNTL_IN_TSKIP(0),
+                       pcdev->base_emma + PRP_CNTL);
+
+       writel(((bytesperline >> 1) << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+       writel(((bytesperline >> 1) << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+       writel(bytesperline,
+                       pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+       writel(0x2ca00565, /* RGB565 */
+                       pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+       writel(0x2ca00565, /* RGB565 */
+                       pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+
+       /* Enable interrupts */
+       writel(PRP_INTR_RDERR |
+                       PRP_INTR_CH1WERR |
+                       PRP_INTR_CH2WERR |
+                       PRP_INTR_CH1FC |
+                       PRP_INTR_CH2FC |
+                       PRP_INTR_LBOVF |
+                       PRP_INTR_CH2OVF,
+                       pcdev->base_emma + PRP_INTR_CNTL);
+}
+
+static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
+               __u32 pixfmt)
+{
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       unsigned long camera_flags, common_flags;
+       int ret = 0;
+       int bytesperline;
+       u32 csicr1 = pcdev->csicr1;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       common_flags = soc_camera_bus_param_compatible(camera_flags,
+                               MX2_BUS_FLAGS);
+       if (!common_flags)
+               return -EINVAL;
+
+       if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+               if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+               else
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+       }
+
+       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+           (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+               if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+               else
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+       }
+
+       ret = icd->ops->set_bus_param(icd, common_flags);
+       if (ret < 0)
+               return ret;
+
+       if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+               csicr1 |= CSICR1_INV_PCLK;
+       if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
+               csicr1 |= CSICR1_SOF_POL;
+       if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH)
+               csicr1 |= CSICR1_HSYNC_POL;
+       if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
+               csicr1 |= CSICR1_SWAP16_EN;
+       if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
+               csicr1 |= CSICR1_EXT_VSYNC;
+       if (pcdev->platform_flags & MX2_CAMERA_CCIR)
+               csicr1 |= CSICR1_CCIR_EN;
+       if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE)
+               csicr1 |= CSICR1_CCIR_MODE;
+       if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK)
+               csicr1 |= CSICR1_GCLK_MODE;
+       if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
+               csicr1 |= CSICR1_INV_DATA;
+       if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
+               csicr1 |= CSICR1_PACK_DIR;
+
+       pcdev->csicr1 = csicr1;
+
+       bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+                       icd->current_fmt->host_fmt);
+       if (bytesperline < 0)
+               return bytesperline;
+
+       if (mx27_camera_emma(pcdev)) {
+               ret = mx27_camera_emma_prp_reset(pcdev);
+               if (ret)
+                       return ret;
+
+               if (pcdev->discard_buffer)
+                       dma_free_coherent(ici->v4l2_dev.dev,
+                               pcdev->discard_size, pcdev->discard_buffer,
+                               pcdev->discard_buffer_dma);
+
+               /*
+                * I didn't manage to properly enable/disable the prp
+                * on a per frame basis during running transfers,
+                * thus we allocate a buffer here and use it to
+                * discard frames when no buffer is available.
+                * Feel free to work on this ;)
+                */
+               pcdev->discard_size = icd->user_height * bytesperline;
+               pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+                               pcdev->discard_size, &pcdev->discard_buffer_dma,
+                               GFP_KERNEL);
+               if (!pcdev->discard_buffer)
+                       return -ENOMEM;
+
+               mx27_camera_emma_buf_init(icd, bytesperline);
+       } else if (cpu_is_mx25()) {
+               writel((bytesperline * icd->user_height) >> 2,
+                               pcdev->base_csi + CSIRXCNT);
+               writel((bytesperline << 16) | icd->user_height,
+                               pcdev->base_csi + CSIIMAG_PARA);
+       }
+
+       writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+       return 0;
+}
+
+static int mx2_camera_set_crop(struct soc_camera_device *icd,
+                               struct v4l2_crop *a)
+{
+       struct v4l2_rect *rect = &a->c;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct v4l2_mbus_framefmt mf;
+       int ret;
+
+       soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+       soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+       ret = v4l2_subdev_call(sd, video, s_crop, a);
+       if (ret < 0)
+               return ret;
+
+       /* The capture device might have changed its output  */
+       ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+               mf.width, mf.height);
+
+       icd->user_width         = mf.width;
+       icd->user_height        = mf.height;
+
+       return ret;
+}
+
+static int mx2_camera_set_fmt(struct soc_camera_device *icd,
+                              struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+       if (!xlate) {
+               dev_warn(icd->dev.parent, "Format %x not found\n",
+                               pix->pixelformat);
+               return -EINVAL;
+       }
+
+       /* eMMA can only do RGB565 */
+       if (mx27_camera_emma(pcdev) && pix->pixelformat != V4L2_PIX_FMT_RGB565)
+               return -EINVAL;
+
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+       if (ret < 0 && ret != -ENOIOCTLCMD)
+               return ret;
+
+       if (mf.code != xlate->code)
+               return -EINVAL;
+
+       pix->width              = mf.width;
+       pix->height             = mf.height;
+       pix->field              = mf.field;
+       pix->colorspace         = mf.colorspace;
+       icd->current_fmt        = xlate;
+
+       return 0;
+}
+
+static int mx2_camera_try_fmt(struct soc_camera_device *icd,
+                                 struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       __u32 pixfmt = pix->pixelformat;
+       unsigned int width_limit;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (pixfmt && !xlate) {
+               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       /* FIXME: implement MX27 limits */
+
+       /* eMMA can only do RGB565 */
+       if (mx27_camera_emma(pcdev) && pixfmt != V4L2_PIX_FMT_RGB565)
+               return -EINVAL;
+
+       /* limit to MX25 hardware capabilities */
+       if (cpu_is_mx25()) {
+               if (xlate->host_fmt->bits_per_sample <= 8)
+                       width_limit = 0xffff * 4;
+               else
+                       width_limit = 0xffff * 2;
+               /* CSIIMAG_PARA limit */
+               if (pix->width > width_limit)
+                       pix->width = width_limit;
+               if (pix->height > 0xffff)
+                       pix->height = 0xffff;
+
+               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;
+               if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */
+                       dev_warn(icd->dev.parent,
+                                       "Image size (%u) above limit\n",
+                                       pix->sizeimage);
+                       return -EINVAL;
+               }
+       }
+
+       /* limit to sensor capabilities */
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       if (mf.field == V4L2_FIELD_ANY)
+               mf.field = V4L2_FIELD_NONE;
+       if (mf.field != V4L2_FIELD_NONE) {
+               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+                               mf.field);
+               return -EINVAL;
+       }
+
+       pix->width      = mf.width;
+       pix->height     = mf.height;
+       pix->field      = mf.field;
+       pix->colorspace = mf.colorspace;
+
+       return 0;
+}
+
+static int mx2_camera_querycap(struct soc_camera_host *ici,
+                              struct v4l2_capability *cap)
+{
+       /* cap->name is set by the friendly caller:-> */
+       strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+       cap->version = MX2_CAM_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int mx2_camera_reqbufs(struct soc_camera_file *icf,
+                             struct v4l2_requestbuffers *p)
+{
+       int i;
+
+       for (i = 0; i < p->count; i++) {
+               struct mx2_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+                                                     struct mx2_buffer, vb);
+               INIT_LIST_HEAD(&buf->vb.queue);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_MACH_MX27
+static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state)
+{
+       struct videobuf_buffer *vb;
+       struct mx2_buffer *buf;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&pcdev->lock, flags);
+
+       if (!pcdev->active) {
+               dev_err(pcdev->dev, "%s called with no active buffer!\n",
+                               __func__);
+               goto out;
+       }
+
+       vb = &pcdev->active->vb;
+       buf = container_of(vb, struct mx2_buffer, vb);
+       WARN_ON(list_empty(&vb->queue));
+       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
+       list_del_init(&vb->queue);
+       vb->state = state;
+       do_gettimeofday(&vb->ts);
+       vb->field_count++;
+
+       wake_up(&vb->done);
+
+       if (list_empty(&pcdev->capture)) {
+               pcdev->active = NULL;
+               goto out;
+       }
+
+       pcdev->active = list_entry(pcdev->capture.next,
+                       struct mx2_buffer, vb.queue);
+
+       vb = &pcdev->active->vb;
+       vb->state = VIDEOBUF_ACTIVE;
+
+       ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
+                       vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ);
+
+       if (ret) {
+               vb->state = VIDEOBUF_ERROR;
+               pcdev->active = NULL;
+               wake_up(&vb->done);
+       }
+
+out:
+       spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx27_camera_dma_err_callback(int channel, void *data, int err)
+{
+       struct mx2_camera_dev *pcdev = data;
+
+       mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
+}
+
+static void mx27_camera_dma_callback(int channel, void *data)
+{
+       struct mx2_camera_dev *pcdev = data;
+
+       mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
+}
+
+#define DMA_REQ_CSI_RX          31 /* FIXME: Add this to a resource */
+
+static int __devinit mx27_camera_dma_init(struct platform_device *pdev,
+               struct mx2_camera_dev *pcdev)
+{
+       int err;
+
+       pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
+       if (pcdev->dma < 0) {
+               dev_err(&pdev->dev, "%s failed to request DMA channel\n",
+                               __func__);
+               return pcdev->dma;
+       }
+
+       err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
+                                       mx27_camera_dma_err_callback, pcdev);
+       if (err) {
+               dev_err(&pdev->dev, "%s failed to set DMA callback\n",
+                               __func__);
+               goto err_out;
+       }
+
+       err = imx_dma_config_channel(pcdev->dma,
+                       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
+                       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+                       DMA_REQ_CSI_RX, 1);
+       if (err) {
+               dev_err(&pdev->dev, "%s failed to config DMA channel\n",
+                               __func__);
+               goto err_out;
+       }
+
+       imx_dma_config_burstlen(pcdev->dma, 64);
+
+       return 0;
+
+err_out:
+       imx_dma_free(pcdev->dma);
+
+       return err;
+}
+#endif /* CONFIG_MACH_MX27 */
+
+static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
+{
+       struct soc_camera_file *icf = file->private_data;
+
+       return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+}
+
+static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = mx2_camera_add_device,
+       .remove         = mx2_camera_remove_device,
+       .set_fmt        = mx2_camera_set_fmt,
+       .set_crop       = mx2_camera_set_crop,
+       .try_fmt        = mx2_camera_try_fmt,
+       .init_videobuf  = mx2_camera_init_videobuf,
+       .reqbufs        = mx2_camera_reqbufs,
+       .poll           = mx2_camera_poll,
+       .querycap       = mx2_camera_querycap,
+       .set_bus_param  = mx2_camera_set_bus_param,
+};
+
+static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
+               int bufnum, int state)
+{
+       struct mx2_buffer *buf;
+       struct videobuf_buffer *vb;
+       unsigned long phys;
+
+       if (!list_empty(&pcdev->active_bufs)) {
+               buf = list_entry(pcdev->active_bufs.next,
+                       struct mx2_buffer, vb.queue);
+
+               BUG_ON(buf->bufnum != bufnum);
+
+               vb = &buf->vb;
+#ifdef DEBUG
+               phys = videobuf_to_dma_contig(vb);
+               if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum)
+                               != phys) {
+                       dev_err(pcdev->dev, "%p != %p\n", phys,
+                                       readl(pcdev->base_emma +
+                                               PRP_DEST_RGB1_PTR +
+                                               4 * bufnum));
+               }
+#endif
+               dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
+                               vb->baddr, vb->bsize);
+
+               list_del(&vb->queue);
+               vb->state = state;
+               do_gettimeofday(&vb->ts);
+               vb->field_count++;
+
+               wake_up(&vb->done);
+       }
+
+       if (list_empty(&pcdev->capture)) {
+               writel(pcdev->discard_buffer_dma, pcdev->base_emma +
+                               PRP_DEST_RGB1_PTR + 4 * bufnum);
+               return;
+       }
+
+       buf = list_entry(pcdev->capture.next,
+                       struct mx2_buffer, vb.queue);
+
+       buf->bufnum = bufnum;
+
+       list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+       vb = &buf->vb;
+       vb->state = VIDEOBUF_ACTIVE;
+
+       phys = videobuf_to_dma_contig(vb);
+       writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
+}
+
+static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
+{
+       struct mx2_camera_dev *pcdev = data;
+       unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
+       struct mx2_buffer *buf;
+
+       if (status & (1 << 7)) { /* overflow */
+               u32 cntl;
+               /*
+                * We only disable channel 1 here since this is the only
+                * enabled channel
+                *
+                * FIXME: the correct DMA overflow handling should be resetting
+                * the buffer, returning an error frame, and continuing with
+                * the next one.
+                */
+               cntl = readl(pcdev->base_emma + PRP_CNTL);
+               writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL);
+               writel(cntl, pcdev->base_emma + PRP_CNTL);
+       }
+       if ((status & (3 << 5)) == (3 << 5)
+                       && !list_empty(&pcdev->active_bufs)) {
+               /*
+                * Both buffers have triggered, process the one we're expecting
+                * to first
+                */
+               buf = list_entry(pcdev->active_bufs.next,
+                       struct mx2_buffer, vb.queue);
+               mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
+               status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
+       }
+       if (status & (1 << 6))
+               mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
+       if (status & (1 << 5))
+               mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
+
+       writel(status, pcdev->base_emma + PRP_INTRSTATUS);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
+{
+       struct resource *res_emma = pcdev->res_emma;
+       int err = 0;
+
+       if (!request_mem_region(res_emma->start, resource_size(res_emma),
+                               MX2_CAM_DRV_NAME)) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
+       if (!pcdev->base_emma) {
+               err = -ENOMEM;
+               goto exit_release;
+       }
+
+       err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
+                       MX2_CAM_DRV_NAME, pcdev);
+       if (err) {
+               dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
+               goto exit_iounmap;
+       }
+
+       pcdev->clk_emma = clk_get(NULL, "emma");
+       if (IS_ERR(pcdev->clk_emma)) {
+               err = PTR_ERR(pcdev->clk_emma);
+               goto exit_free_irq;
+       }
+
+       clk_enable(pcdev->clk_emma);
+
+       err = mx27_camera_emma_prp_reset(pcdev);
+       if (err)
+               goto exit_clk_emma_put;
+
+       return err;
+
+exit_clk_emma_put:
+       clk_disable(pcdev->clk_emma);
+       clk_put(pcdev->clk_emma);
+exit_free_irq:
+       free_irq(pcdev->irq_emma, pcdev);
+exit_iounmap:
+       iounmap(pcdev->base_emma);
+exit_release:
+       release_mem_region(res_emma->start, resource_size(res_emma));
+out:
+       return err;
+}
+
+static int __devinit mx2_camera_probe(struct platform_device *pdev)
+{
+       struct mx2_camera_dev *pcdev;
+       struct resource *res_csi, *res_emma;
+       void __iomem *base_csi;
+       int irq_csi, irq_emma;
+       irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq
+               : mx27_camera_irq;
+       int err = 0;
+
+       dev_dbg(&pdev->dev, "initialising\n");
+
+       res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq_csi = platform_get_irq(pdev, 0);
+       if (res_csi == NULL || irq_csi < 0) {
+               dev_err(&pdev->dev, "Missing platform resources data\n");
+               err = -ENODEV;
+               goto exit;
+       }
+
+       pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+       if (!pcdev) {
+               dev_err(&pdev->dev, "Could not allocate pcdev\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       pcdev->clk_csi = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pcdev->clk_csi)) {
+               err = PTR_ERR(pcdev->clk_csi);
+               goto exit_kfree;
+       }
+
+       dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n",
+                       clk_get_rate(pcdev->clk_csi));
+
+       /* Initialize DMA */
+#ifdef CONFIG_MACH_MX27
+       if (cpu_is_mx27()) {
+               err = mx27_camera_dma_init(pdev, pcdev);
+               if (err)
+                       goto exit_clk_put;
+       }
+#endif /* CONFIG_MACH_MX27 */
+
+       pcdev->res_csi = res_csi;
+       pcdev->pdata = pdev->dev.platform_data;
+       if (pcdev->pdata) {
+               long rate;
+
+               pcdev->platform_flags = pcdev->pdata->flags;
+
+               rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
+               if (rate <= 0) {
+                       err = -ENODEV;
+                       goto exit_dma_free;
+               }
+               err = clk_set_rate(pcdev->clk_csi, rate);
+               if (err < 0)
+                       goto exit_dma_free;
+       }
+
+       INIT_LIST_HEAD(&pcdev->capture);
+       INIT_LIST_HEAD(&pcdev->active_bufs);
+       spin_lock_init(&pcdev->lock);
+
+       /*
+        * Request the regions.
+        */
+       if (!request_mem_region(res_csi->start, resource_size(res_csi),
+                               MX2_CAM_DRV_NAME)) {
+               err = -EBUSY;
+               goto exit_dma_free;
+       }
+
+       base_csi = ioremap(res_csi->start, resource_size(res_csi));
+       if (!base_csi) {
+               err = -ENOMEM;
+               goto exit_release;
+       }
+       pcdev->irq_csi = irq_csi;
+       pcdev->base_csi = base_csi;
+       pcdev->base_dma = res_csi->start;
+       pcdev->dev = &pdev->dev;
+
+       err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0,
+                       MX2_CAM_DRV_NAME, pcdev);
+       if (err) {
+               dev_err(pcdev->dev, "Camera interrupt register failed \n");
+               goto exit_iounmap;
+       }
+
+       if (cpu_is_mx27()) {
+               /* EMMA support */
+               res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               irq_emma = platform_get_irq(pdev, 1);
+
+               if (res_emma && irq_emma >= 0) {
+                       dev_info(&pdev->dev, "Using EMMA\n");
+                       pcdev->use_emma = 1;
+                       pcdev->res_emma = res_emma;
+                       pcdev->irq_emma = irq_emma;
+                       if (mx27_camera_emma_init(pcdev))
+                               goto exit_free_irq;
+               }
+       }
+
+       pcdev->soc_host.drv_name        = MX2_CAM_DRV_NAME,
+       pcdev->soc_host.ops             = &mx2_soc_camera_host_ops,
+       pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.v4l2_dev.dev    = &pdev->dev;
+       pcdev->soc_host.nr              = pdev->id;
+       err = soc_camera_host_register(&pcdev->soc_host);
+       if (err)
+               goto exit_free_emma;
+
+       return 0;
+
+exit_free_emma:
+       if (mx27_camera_emma(pcdev)) {
+               free_irq(pcdev->irq_emma, pcdev);
+               clk_disable(pcdev->clk_emma);
+               clk_put(pcdev->clk_emma);
+               iounmap(pcdev->base_emma);
+               release_mem_region(res_emma->start, resource_size(res_emma));
+       }
+exit_free_irq:
+       free_irq(pcdev->irq_csi, pcdev);
+exit_iounmap:
+       iounmap(base_csi);
+exit_release:
+       release_mem_region(res_csi->start, resource_size(res_csi));
+exit_dma_free:
+#ifdef CONFIG_MACH_MX27
+       if (cpu_is_mx27())
+               imx_dma_free(pcdev->dma);
+exit_clk_put:
+       clk_put(pcdev->clk_csi);
+#endif /* CONFIG_MACH_MX27 */
+exit_kfree:
+       kfree(pcdev);
+exit:
+       return err;
+}
+
+static int __devexit mx2_camera_remove(struct platform_device *pdev)
+{
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct mx2_camera_dev *pcdev = container_of(soc_host,
+                       struct mx2_camera_dev, soc_host);
+       struct resource *res;
+
+       clk_put(pcdev->clk_csi);
+#ifdef CONFIG_MACH_MX27
+       if (cpu_is_mx27())
+               imx_dma_free(pcdev->dma);
+#endif /* CONFIG_MACH_MX27 */
+       free_irq(pcdev->irq_csi, pcdev);
+       if (mx27_camera_emma(pcdev))
+               free_irq(pcdev->irq_emma, pcdev);
+
+       soc_camera_host_unregister(&pcdev->soc_host);
+
+       iounmap(pcdev->base_csi);
+
+       if (mx27_camera_emma(pcdev)) {
+               clk_disable(pcdev->clk_emma);
+               clk_put(pcdev->clk_emma);
+               iounmap(pcdev->base_emma);
+               res = pcdev->res_emma;
+               release_mem_region(res->start, resource_size(res));
+       }
+
+       res = pcdev->res_csi;
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(pcdev);
+
+       dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
+
+       return 0;
+}
+
+static struct platform_driver mx2_camera_driver = {
+       .driver         = {
+               .name   = MX2_CAM_DRV_NAME,
+       },
+       .remove         = __devexit_p(mx2_camera_remove),
+};
+
+
+static int __init mx2_camera_init(void)
+{
+       return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
+}
+
+static void __exit mx2_camera_exit(void)
+{
+       return platform_driver_unregister(&mx2_camera_driver);
+}
+
+module_init(mx2_camera_init);
+module_exit(mx2_camera_exit);
+
+MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
+MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
+MODULE_LICENSE("GPL");
index 929073e792c904717014070d37802faa67c4d9e9..4ed51b1552e1afdf7d8017412db95a047e91821e 100644 (file)
@@ -2545,19 +2545,11 @@ static int __init omap_vout_probe(struct platform_device *pdev)
                        /* set the update mode */
                        if (def_display->caps &
                                        OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
-                               if (dssdrv->enable_te)
-                                       dssdrv->enable_te(def_display, 1);
-                               if (dssdrv->set_update_mode)
-                                       dssdrv->set_update_mode(def_display,
-                                                       OMAP_DSS_UPDATE_AUTO);
-#else  /* MANUAL_UPDATE */
                                if (dssdrv->enable_te)
                                        dssdrv->enable_te(def_display, 0);
                                if (dssdrv->set_update_mode)
                                        dssdrv->set_update_mode(def_display,
                                                        OMAP_DSS_UPDATE_MANUAL);
-#endif
                        } else {
                                if (dssdrv->set_update_mode)
                                        dssdrv->set_update_mode(def_display,
index f85b2ed8a2d888d661c4df567fc2a4c4638bd5ee..926a5aa6f7f81951ac639c534a05ea0e4c5ac914 100644 (file)
@@ -426,7 +426,7 @@ static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
                             dma->direction);
                dma->direction = DMA_NONE;
        } else {
-               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+               videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
                videobuf_dma_free(videobuf_to_dma(vb));
        }
 
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
deleted file mode 100644 (file)
index a109120..0000000
+++ /dev/null
@@ -1,5995 +0,0 @@
-/*
- * OmniVision OV511 Camera-to-USB Bridge Driver
- *
- * Copyright (c) 1999-2003 Mark W. McClelland
- * Original decompression code Copyright 1998-2000 OmniVision Technologies
- * Many improvements by Bret Wallach <bwallac1@san.rr.com>
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- * Snapshot code by Kevin Moore
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka <claudio@conectiva.com>
- * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * URB error messages from pwc driver by Nemosoft
- * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
- * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
- *
- * Based on the Linux CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt.
- *
- * Please see the file: Documentation/usb/ov511.txt
- * and the website at:  http://alpha.dyndns.org/ov511
- * for more info.
- *
- * This program is free software; 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/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <asm/processor.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#if defined (__i386__)
-       #include <asm/cpufeature.h>
-#endif
-
-#include "ov511.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.64 for Linux 2.5"
-#define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "ov511 USB Camera Driver"
-
-#define OV511_I2C_RETRIES 3
-#define ENABLE_Y_QUANTABLE 1
-#define ENABLE_UV_QUANTABLE 1
-
-#define OV511_MAX_UNIT_VIDEO 16
-
-/* Pixel count * bytes per YUV420 pixel (1.5) */
-#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
-
-#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
-
-/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
-#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
-
-#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
-/**********************************************************************
- * Module Parameters
- * (See ov511.txt for detailed descriptions of these)
- **********************************************************************/
-
-/* These variables (and all static globals) default to zero */
-static int autobright          = 1;
-static int autogain            = 1;
-static int autoexp             = 1;
-static int debug;
-static int snapshot;
-static int cams                        = 1;
-static int compress;
-static int testpat;
-static int dumppix;
-static int led                         = 1;
-static int dump_bridge;
-static int dump_sensor;
-static int printph;
-static int phy                 = 0x1f;
-static int phuv                        = 0x05;
-static int pvy                 = 0x06;
-static int pvuv                        = 0x06;
-static int qhy                 = 0x14;
-static int qhuv                        = 0x03;
-static int qvy                 = 0x04;
-static int qvuv                        = 0x04;
-static int lightfreq;
-static int bandingfilter;
-static int clockdiv            = -1;
-static int packetsize          = -1;
-static int framedrop           = -1;
-static int fastset;
-static int force_palette;
-static int backlight;
-/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
-static unsigned long ov511_devused;
-static int unit_video[OV511_MAX_UNIT_VIDEO];
-static int remove_zeros;
-static int mirror;
-static int ov518_color;
-
-module_param(autobright, int, 0);
-MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
-module_param(autogain, int, 0);
-MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
-module_param(autoexp, int, 0);
-MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
-  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
-module_param(snapshot, int, 0);
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
-module_param(cams, int, 0);
-MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
-module_param(compress, int, 0);
-MODULE_PARM_DESC(compress, "Turn on compression");
-module_param(testpat, int, 0);
-MODULE_PARM_DESC(testpat,
-  "Replace image with vertical bar testpattern (only partially working)");
-module_param(dumppix, int, 0);
-MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
-module_param(led, int, 0);
-MODULE_PARM_DESC(led,
-  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
-module_param(dump_bridge, int, 0);
-MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
-module_param(dump_sensor, int, 0);
-MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
-module_param(printph, int, 0);
-MODULE_PARM_DESC(printph, "Print frame start/end headers");
-module_param(phy, int, 0);
-MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
-module_param(phuv, int, 0);
-MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
-module_param(pvy, int, 0);
-MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
-module_param(pvuv, int, 0);
-MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
-module_param(qhy, int, 0);
-MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
-module_param(qhuv, int, 0);
-MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
-module_param(qvy, int, 0);
-MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
-module_param(qvuv, int, 0);
-MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
-module_param(lightfreq, int, 0);
-MODULE_PARM_DESC(lightfreq,
-  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
-module_param(bandingfilter, int, 0);
-MODULE_PARM_DESC(bandingfilter,
-  "Enable banding filter (to reduce effects of fluorescent lighting)");
-module_param(clockdiv, int, 0);
-MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
-module_param(packetsize, int, 0);
-MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
-module_param(framedrop, int, 0);
-MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
-module_param(fastset, int, 0);
-MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
-module_param(force_palette, int, 0);
-MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-module_param(backlight, int, 0);
-MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static unsigned int num_uv;
-module_param_array(unit_video, int, &num_uv, 0);
-MODULE_PARM_DESC(unit_video,
-  "Force use of specific minor number(s). 0 is not allowed.");
-module_param(remove_zeros, int, 0);
-MODULE_PARM_DESC(remove_zeros,
-  "Remove zero-padding from uncompressed incoming data");
-module_param(mirror, int, 0);
-MODULE_PARM_DESC(mirror, "Reverse image horizontally");
-module_param(ov518_color, int, 0);
-MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/**********************************************************************
- * Miscellaneous Globals
- **********************************************************************/
-
-static struct usb_driver ov511_driver;
-
-/* Number of times to retry a failed I2C transaction. Increase this if you
- * are getting "Failed to read sensor ID..." */
-static const int i2c_detect_tries = 5;
-
-static struct usb_device_id device_table [] = {
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-       { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-       { }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
-
-/**********************************************************************
- * Symbolic Names
- **********************************************************************/
-
-/* Known OV511-based cameras */
-static struct symbolic_list camlist[] = {
-       {   0, "Generic Camera (no ID)" },
-       {   1, "Mustek WCam 3X" },
-       {   3, "D-Link DSB-C300" },
-       {   4, "Generic OV511/OV7610" },
-       {   5, "Puretek PT-6007" },
-       {   6, "Lifeview USB Life TV (NTSC)" },
-       {  21, "Creative Labs WebCam 3" },
-       {  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
-       {  36, "Koala-Cam" },
-       {  38, "Lifeview USB Life TV (PAL)" },
-       {  41, "Samsung Anycam MPC-M10" },
-       {  43, "Mtekvision Zeca MV402" },
-       {  46, "Suma eON" },
-       {  70, "Lifeview USB Life TV (PAL/SECAM)" },
-       { 100, "Lifeview RoboCam" },
-       { 102, "AverMedia InterCam Elite" },
-       { 112, "MediaForte MV300" },    /* or OV7110 evaluation kit */
-       { 134, "Ezonics EZCam II" },
-       { 192, "Webeye 2000B" },
-       { 253, "Alpha Vision Tech. AlphaCam SE" },
-       {  -1, NULL }
-};
-
-/* Video4Linux1 Palettes */
-static struct symbolic_list v4l1_plist[] = {
-       { VIDEO_PALETTE_GREY,   "GREY" },
-       { VIDEO_PALETTE_HI240,  "HI240" },
-       { VIDEO_PALETTE_RGB565, "RGB565" },
-       { VIDEO_PALETTE_RGB24,  "RGB24" },
-       { VIDEO_PALETTE_RGB32,  "RGB32" },
-       { VIDEO_PALETTE_RGB555, "RGB555" },
-       { VIDEO_PALETTE_YUV422, "YUV422" },
-       { VIDEO_PALETTE_YUYV,   "YUYV" },
-       { VIDEO_PALETTE_UYVY,   "UYVY" },
-       { VIDEO_PALETTE_YUV420, "YUV420" },
-       { VIDEO_PALETTE_YUV411, "YUV411" },
-       { VIDEO_PALETTE_RAW,    "RAW" },
-       { VIDEO_PALETTE_YUV422P,"YUV422P" },
-       { VIDEO_PALETTE_YUV411P,"YUV411P" },
-       { VIDEO_PALETTE_YUV420P,"YUV420P" },
-       { VIDEO_PALETTE_YUV410P,"YUV410P" },
-       { -1, NULL }
-};
-
-static struct symbolic_list brglist[] = {
-       { BRG_OV511,            "OV511" },
-       { BRG_OV511PLUS,        "OV511+" },
-       { BRG_OV518,            "OV518" },
-       { BRG_OV518PLUS,        "OV518+" },
-       { -1, NULL }
-};
-
-static struct symbolic_list senlist[] = {
-       { SEN_OV76BE,   "OV76BE" },
-       { SEN_OV7610,   "OV7610" },
-       { SEN_OV7620,   "OV7620" },
-       { SEN_OV7620AE, "OV7620AE" },
-       { SEN_OV6620,   "OV6620" },
-       { SEN_OV6630,   "OV6630" },
-       { SEN_OV6630AE, "OV6630AE" },
-       { SEN_OV6630AF, "OV6630AF" },
-       { SEN_OV8600,   "OV8600" },
-       { SEN_KS0127,   "KS0127" },
-       { SEN_KS0127B,  "KS0127B" },
-       { SEN_SAA7111A, "SAA7111A" },
-       { -1, NULL }
-};
-
-/* URB error codes: */
-static struct symbolic_list urb_errlist[] = {
-       { -ENOSR,       "Buffer error (overrun)" },
-       { -EPIPE,       "Stalled (device not responding)" },
-       { -EOVERFLOW,   "Babble (device sends too much data)" },
-       { -EPROTO,      "Bit-stuff error (bad cable?)" },
-       { -EILSEQ,      "CRC/Timeout (bad cable?)" },
-       { -ETIME,       "Device does not respond to token" },
-       { -ETIMEDOUT,   "Device does not respond to command" },
-       { -1, NULL }
-};
-
-/**********************************************************************
- * 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);
-}
-
-/**********************************************************************
- *
- * Register I/O
- *
- **********************************************************************/
-
-/* Write an OV51x register */
-static int
-reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       mutex_lock(&ov->cbuf_lock);
-       ov->cbuf[0] = value;
-       rc = usb_control_msg(ov->dev,
-                            usb_sndctrlpipe(ov->dev, 0),
-                            (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
-                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-       mutex_unlock(&ov->cbuf_lock);
-
-       if (rc < 0)
-               err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
-
-       return rc;
-}
-
-/* Read from an OV51x register */
-/* returns: negative is error, pos or zero is data */
-static int
-reg_r(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->cbuf_lock);
-       rc = usb_control_msg(ov->dev,
-                            usb_rcvctrlpipe(ov->dev, 0),
-                            (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
-                            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-
-       if (rc < 0) {
-               err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
-       } else {
-               rc = ov->cbuf[0];
-               PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-       }
-
-       mutex_unlock(&ov->cbuf_lock);
-
-       return rc;
-}
-
-/*
- * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-reg_w_mask(struct usb_ov511 *ov,
-          unsigned char reg,
-          unsigned char value,
-          unsigned char mask)
-{
-       int ret;
-       unsigned char oldval, newval;
-
-       ret = reg_r(ov, reg);
-       if (ret < 0)
-               return ret;
-
-       oldval = (unsigned char) ret;
-       oldval &= (~mask);              /* Clear the masked bits */
-       value &= mask;                  /* Enforce mask on value */
-       newval = oldval | value;        /* Set the desired bits */
-
-       return (reg_w(ov, reg, newval));
-}
-
-/*
- * Writes multiple (n) byte value to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce).
- */
-static int
-ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
-
-       mutex_lock(&ov->cbuf_lock);
-
-       *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
-
-       rc = usb_control_msg(ov->dev,
-                            usb_sndctrlpipe(ov->dev, 0),
-                            1 /* REG_IO */,
-                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, ov->cbuf, n, 1000);
-       mutex_unlock(&ov->cbuf_lock);
-
-       if (rc < 0)
-               err("reg write multiple: error %d: %s", rc,
-                   symbolic(urb_errlist, rc));
-
-       return rc;
-}
-
-static int
-ov511_upload_quan_tables(struct usb_ov511 *ov)
-{
-       unsigned char *pYTable = yQuanTable511;
-       unsigned char *pUVTable = uvQuanTable511;
-       unsigned char val0, val1;
-       int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-       PDEBUG(4, "Uploading quantization tables");
-
-       for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
-               if (ENABLE_Y_QUANTABLE) {
-                       val0 = *pYTable++;
-                       val1 = *pYTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               if (ENABLE_UV_QUANTABLE) {
-                       val0 = *pUVTable++;
-                       val1 = *pUVTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               reg++;
-       }
-
-       return 0;
-}
-
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
-ov518_upload_quan_tables(struct usb_ov511 *ov)
-{
-       unsigned char *pYTable = yQuanTable518;
-       unsigned char *pUVTable = uvQuanTable518;
-       unsigned char val0, val1;
-       int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-       PDEBUG(4, "Uploading quantization tables");
-
-       for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
-               if (ENABLE_Y_QUANTABLE) {
-                       val0 = *pYTable++;
-                       val1 = *pYTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               if (ENABLE_UV_QUANTABLE) {
-                       val0 = *pUVTable++;
-                       val1 = *pUVTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               reg++;
-       }
-
-       return 0;
-}
-
-static int
-ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
-{
-       int rc;
-
-       /* Setting bit 0 not allowed on 518/518Plus */
-       if (ov->bclass == BCL_OV518)
-               reset_type &= 0xfe;
-
-       PDEBUG(4, "Reset: type=0x%02X", reset_type);
-
-       rc = reg_w(ov, R51x_SYS_RESET, reset_type);
-       rc = reg_w(ov, R51x_SYS_RESET, 0);
-
-       if (rc < 0)
-               err("reset: command failed");
-
-       return rc;
-}
-
-/**********************************************************************
- *
- * Low-level I2C I/O functions
- *
- **********************************************************************/
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_w(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_write_internal(struct usb_ov511 *ov,
-                        unsigned char reg,
-                        unsigned char value)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* Select camera register */
-       rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-       if (rc < 0)
-               return rc;
-
-       /* Write "value" to I2C data port of OV511 */
-       rc = reg_w(ov, R51x_I2C_DATA, value);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 3-byte write cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x01);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/* NOTE: Do not call this function directly! */
-static int
-ov511_i2c_write_internal(struct usb_ov511 *ov,
-                        unsigned char reg,
-                        unsigned char value)
-{
-       int rc, retries;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* Three byte write cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Select camera register */
-               rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-               if (rc < 0)
-                       break;
-
-               /* Write "value" to I2C data port of OV511 */
-               rc = reg_w(ov, R51x_I2C_DATA, value);
-               if (rc < 0)
-                       break;
-
-               /* Initiate 3-byte write cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x01);
-               if (rc < 0)
-                       break;
-
-               /* Retry until idle */
-               do {
-                       rc = reg_r(ov, R511_I2C_CTL);
-               } while (rc > 0 && ((rc&1) == 0));
-               if (rc < 0)
-                       break;
-
-               /* Ack? */
-               if ((rc&2) == 0) {
-                       rc = 0;
-                       break;
-               }
-#if 0
-               /* I2C abort */
-               reg_w(ov, R511_I2C_CTL, 0x10);
-#endif
-               if (--retries < 0) {
-                       err("i2c write retries exhausted");
-                       rc = -1;
-                       break;
-               }
-       }
-
-       return rc;
-}
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_r(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc, value;
-
-       /* Select camera register */
-       rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 2-byte write cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x03);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 2-byte read cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x05);
-       if (rc < 0)
-               return rc;
-
-       value = reg_r(ov, R51x_I2C_DATA);
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       return value;
-}
-
-/* NOTE: Do not call this function directly!
- * returns: negative is error, pos or zero is data */
-static int
-ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc, value, retries;
-
-       /* Two byte write cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Select camera register */
-               rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-               if (rc < 0)
-                       return rc;
-
-               /* Initiate 2-byte write cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x03);
-               if (rc < 0)
-                       return rc;
-
-               /* Retry until idle */
-               do {
-                       rc = reg_r(ov, R511_I2C_CTL);
-               } while (rc > 0 && ((rc & 1) == 0));
-               if (rc < 0)
-                       return rc;
-
-               if ((rc&2) == 0) /* Ack? */
-                       break;
-
-               /* I2C abort */
-               reg_w(ov, R511_I2C_CTL, 0x10);
-
-               if (--retries < 0) {
-                       err("i2c write retries exhausted");
-                       return -1;
-               }
-       }
-
-       /* Two byte read cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Initiate 2-byte read cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x05);
-               if (rc < 0)
-                       return rc;
-
-               /* Retry until idle */
-               do {
-                       rc = reg_r(ov, R511_I2C_CTL);
-               } while (rc > 0 && ((rc&1) == 0));
-               if (rc < 0)
-                       return rc;
-
-               if ((rc&2) == 0) /* Ack? */
-                       break;
-
-               /* I2C abort */
-               rc = reg_w(ov, R511_I2C_CTL, 0x10);
-               if (rc < 0)
-                       return rc;
-
-               if (--retries < 0) {
-                       err("i2c read retries exhausted");
-                       return -1;
-               }
-       }
-
-       value = reg_r(ov, R51x_I2C_DATA);
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* This is needed to make i2c_w() work */
-       rc = reg_w(ov, R511_I2C_CTL, 0x05);
-       if (rc < 0)
-               return rc;
-
-       return value;
-}
-
-/* returns: negative is error, pos or zero is data */
-static int
-i2c_r(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_read_internal(ov, reg);
-       else
-               rc = ov511_i2c_read_internal(ov, reg);
-
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-static int
-i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_write_internal(ov, reg, value);
-       else
-               rc = ov511_i2c_write_internal(ov, reg, value);
-
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
-                             unsigned char reg,
-                             unsigned char value,
-                             unsigned char mask)
-{
-       int rc;
-       unsigned char oldval, newval;
-
-       if (mask == 0xff) {
-               newval = value;
-       } else {
-               if (ov->bclass == BCL_OV518)
-                       rc = ov518_i2c_read_internal(ov, reg);
-               else
-                       rc = ov511_i2c_read_internal(ov, reg);
-               if (rc < 0)
-                       return rc;
-
-               oldval = (unsigned char) rc;
-               oldval &= (~mask);              /* Clear the masked bits */
-               value &= mask;                  /* Enforce mask on value */
-               newval = oldval | value;        /* Set the desired bits */
-       }
-
-       if (ov->bclass == BCL_OV518)
-               return (ov518_i2c_write_internal(ov, reg, newval));
-       else
-               return (ov511_i2c_write_internal(ov, reg, newval));
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-i2c_w_mask(struct usb_ov511 *ov,
-          unsigned char reg,
-          unsigned char value,
-          unsigned char mask)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-/* Set the read and write slave IDs. The "slave" argument is the write slave,
- * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
- * when calling this. This should not be called from outside the i2c I/O
- * functions.
- */
-static int
-i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
-{
-       int rc;
-
-       rc = reg_w(ov, R51x_I2C_W_SID, slave);
-       if (rc < 0)
-               return rc;
-
-       rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
-i2c_w_slave(struct usb_ov511 *ov,
-           unsigned char slave,
-           unsigned char reg,
-           unsigned char value,
-           unsigned char mask)
-{
-       int rc = 0;
-
-       mutex_lock(&ov->i2c_lock);
-
-       /* Set new slave IDs */
-       rc = i2c_set_slave_internal(ov, slave);
-       if (rc < 0)
-               goto out;
-
-       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-
-out:
-       /* Restore primary IDs */
-       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-               err("Couldn't restore primary I2C slave");
-
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-/* Read from a specific I2C slave ID and register */
-static int
-i2c_r_slave(struct usb_ov511 *ov,
-           unsigned char slave,
-           unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       /* Set new slave IDs */
-       rc = i2c_set_slave_internal(ov, slave);
-       if (rc < 0)
-               goto out;
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_read_internal(ov, reg);
-       else
-               rc = ov511_i2c_read_internal(ov, reg);
-
-out:
-       /* Restore primary IDs */
-       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-               err("Couldn't restore primary I2C slave");
-
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
-ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       rc = i2c_set_slave_internal(ov, sid);
-       if (rc < 0)
-               goto out;
-
-       // FIXME: Is this actually necessary?
-       rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-out:
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-static int
-write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
-{
-       int rc;
-
-       while (pRegvals->bus != OV511_DONE_BUS) {
-               if (pRegvals->bus == OV511_REG_BUS) {
-                       if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-                               return rc;
-               } else if (pRegvals->bus == OV511_I2C_BUS) {
-                       if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-                               return rc;
-               } else {
-                       err("Bad regval array");
-                       return -1;
-               }
-               pRegvals++;
-       }
-       return 0;
-}
-
-#ifdef OV511_DEBUG
-static void
-dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-       int i, rc;
-
-       for (i = reg1; i <= regn; i++) {
-               rc = i2c_r(ov, i);
-               dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc);
-       }
-}
-
-static void
-dump_i2c_regs(struct usb_ov511 *ov)
-{
-       dev_info(&ov->dev->dev, "I2C REGS\n");
-       dump_i2c_range(ov, 0x00, 0x7C);
-}
-
-static void
-dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-       int i, rc;
-
-       for (i = reg1; i <= regn; i++) {
-               rc = reg_r(ov, i);
-               dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc);
-       }
-}
-
-static void
-ov511_dump_regs(struct usb_ov511 *ov)
-{
-       dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n");
-       dump_reg_range(ov, 0x10, 0x1f);
-       dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n");
-       dump_reg_range(ov, 0x20, 0x23);
-       dev_info(&ov->dev->dev, "ISO FIFO REGS\n");
-       dump_reg_range(ov, 0x30, 0x31);
-       dev_info(&ov->dev->dev, "PIO REGS\n");
-       dump_reg_range(ov, 0x38, 0x39);
-       dump_reg_range(ov, 0x3e, 0x3e);
-       dev_info(&ov->dev->dev, "I2C REGS\n");
-       dump_reg_range(ov, 0x40, 0x49);
-       dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n");
-       dump_reg_range(ov, 0x50, 0x55);
-       dump_reg_range(ov, 0x5e, 0x5f);
-       dev_info(&ov->dev->dev, "OmniCE REGS\n");
-       dump_reg_range(ov, 0x70, 0x79);
-       /* NOTE: Quantization tables are not readable. You will get the value
-        * in reg. 0x79 for every table register */
-       dump_reg_range(ov, 0x80, 0x9f);
-       dump_reg_range(ov, 0xa0, 0xbf);
-
-}
-
-static void
-ov518_dump_regs(struct usb_ov511 *ov)
-{
-       dev_info(&ov->dev->dev, "VIDEO MODE REGS\n");
-       dump_reg_range(ov, 0x20, 0x2f);
-       dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n");
-       dump_reg_range(ov, 0x30, 0x3f);
-       dev_info(&ov->dev->dev, "I2C REGS\n");
-       dump_reg_range(ov, 0x40, 0x4f);
-       dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n");
-       dump_reg_range(ov, 0x50, 0x5f);
-       dev_info(&ov->dev->dev, "60 - 6F\n");
-       dump_reg_range(ov, 0x60, 0x6f);
-       dev_info(&ov->dev->dev, "70 - 7F\n");
-       dump_reg_range(ov, 0x70, 0x7f);
-       dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n");
-       dump_reg_range(ov, 0x80, 0x8f);
-       dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n");
-       dump_reg_range(ov, 0x90, 0x9f);
-       dev_info(&ov->dev->dev, "A0 - BF\n");
-       dump_reg_range(ov, 0xa0, 0xbf);
-       dev_info(&ov->dev->dev, "CBR\n");
-       dump_reg_range(ov, 0xc0, 0xcf);
-}
-#endif
-
-/*****************************************************************************/
-
-/* Temporarily stops OV511 from functioning. Must do this before changing
- * registers while the camera is streaming */
-static inline int
-ov51x_stop(struct usb_ov511 *ov)
-{
-       PDEBUG(4, "stopping");
-       ov->stopped = 1;
-       if (ov->bclass == BCL_OV518)
-               return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
-       else
-               return (reg_w(ov, R51x_SYS_RESET, 0x3d));
-}
-
-/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
- * actually stopped (for performance). */
-static inline int
-ov51x_restart(struct usb_ov511 *ov)
-{
-       if (ov->stopped) {
-               PDEBUG(4, "restarting");
-               ov->stopped = 0;
-
-               /* Reinitialize the stream */
-               if (ov->bclass == BCL_OV518)
-                       reg_w(ov, 0x2f, 0x80);
-
-               return (reg_w(ov, R51x_SYS_RESET, 0x00));
-       }
-
-       return 0;
-}
-
-/* Sleeps until no frames are active. Returns !0 if got signal */
-static int
-ov51x_wait_frames_inactive(struct usb_ov511 *ov)
-{
-       return wait_event_interruptible(ov->wq, ov->curframe < 0);
-}
-
-/* Resets the hardware snapshot button */
-static void
-ov51x_clear_snapshot(struct usb_ov511 *ov)
-{
-       if (ov->bclass == BCL_OV511) {
-               reg_w(ov, R51x_SYS_SNAP, 0x00);
-               reg_w(ov, R51x_SYS_SNAP, 0x02);
-               reg_w(ov, R51x_SYS_SNAP, 0x00);
-       } else if (ov->bclass == BCL_OV518) {
-               dev_warn(&ov->dev->dev,
-                        "snapshot reset not supported yet on OV518(+)\n");
-       } else {
-               dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
-       }
-}
-
-#if 0
-/* Checks the status of the snapshot button. Returns 1 if it was pressed since
- * it was last cleared, and zero in all other cases (including errors) */
-static int
-ov51x_check_snapshot(struct usb_ov511 *ov)
-{
-       int ret, status = 0;
-
-       if (ov->bclass == BCL_OV511) {
-               ret = reg_r(ov, R51x_SYS_SNAP);
-               if (ret < 0) {
-                       dev_err(&ov->dev->dev,
-                               "Error checking snspshot status (%d)\n", ret);
-               } else if (ret & 0x08) {
-                       status = 1;
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               dev_warn(&ov->dev->dev,
-                        "snapshot check not supported yet on OV518(+)\n");
-       } else {
-               dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
-       }
-
-       return status;
-}
-#endif
-
-/* This does an initial reset of an OmniVision sensor and ensures that I2C
- * is synchronized. Returns <0 for failure.
- */
-static int
-init_ov_sensor(struct usb_ov511 *ov)
-{
-       int i, success;
-
-       /* Reset the sensor */
-       if (i2c_w(ov, 0x12, 0x80) < 0)
-               return -EIO;
-
-       /* Wait for it to initialize */
-       msleep(150);
-
-       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
-               if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-                   (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-                       success = 1;
-                       continue;
-               }
-
-               /* Reset the sensor */
-               if (i2c_w(ov, 0x12, 0x80) < 0)
-                       return -EIO;
-               /* Wait for it to initialize */
-               msleep(150);
-               /* Dummy read to sync I2C */
-               if (i2c_r(ov, 0x00) < 0)
-                       return -EIO;
-       }
-
-       if (!success)
-               return -EIO;
-
-       PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
-       return 0;
-}
-
-static int
-ov511_set_packet_size(struct usb_ov511 *ov, int size)
-{
-       int alt, mult;
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       mult = size >> 5;
-
-       if (ov->bridge == BRG_OV511) {
-               if (size == 0)
-                       alt = OV511_ALT_SIZE_0;
-               else if (size == 257)
-                       alt = OV511_ALT_SIZE_257;
-               else if (size == 513)
-                       alt = OV511_ALT_SIZE_513;
-               else if (size == 769)
-                       alt = OV511_ALT_SIZE_769;
-               else if (size == 993)
-                       alt = OV511_ALT_SIZE_993;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (size == 0)
-                       alt = OV511PLUS_ALT_SIZE_0;
-               else if (size == 33)
-                       alt = OV511PLUS_ALT_SIZE_33;
-               else if (size == 129)
-                       alt = OV511PLUS_ALT_SIZE_129;
-               else if (size == 257)
-                       alt = OV511PLUS_ALT_SIZE_257;
-               else if (size == 385)
-                       alt = OV511PLUS_ALT_SIZE_385;
-               else if (size == 513)
-                       alt = OV511PLUS_ALT_SIZE_513;
-               else if (size == 769)
-                       alt = OV511PLUS_ALT_SIZE_769;
-               else if (size == 961)
-                       alt = OV511PLUS_ALT_SIZE_961;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else {
-               err("Set packet size: Invalid bridge type");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
-
-       if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
-               return -EIO;
-
-       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-               err("Set packet size: set interface error");
-               return -EBUSY;
-       }
-
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       ov->packet_size = size;
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
- * optional packet number byte. The actual size *is* stored in ov->packet_size,
- * though. */
-static int
-ov518_set_packet_size(struct usb_ov511 *ov, int size)
-{
-       int alt;
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       if (ov->bclass == BCL_OV518) {
-               if (size == 0)
-                       alt = OV518_ALT_SIZE_0;
-               else if (size == 128)
-                       alt = OV518_ALT_SIZE_128;
-               else if (size == 256)
-                       alt = OV518_ALT_SIZE_256;
-               else if (size == 384)
-                       alt = OV518_ALT_SIZE_384;
-               else if (size == 512)
-                       alt = OV518_ALT_SIZE_512;
-               else if (size == 640)
-                       alt = OV518_ALT_SIZE_640;
-               else if (size == 768)
-                       alt = OV518_ALT_SIZE_768;
-               else if (size == 896)
-                       alt = OV518_ALT_SIZE_896;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else {
-               err("Set packet size: Invalid bridge type");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d, alt=%d", size, alt);
-
-       ov->packet_size = size;
-       if (size > 0) {
-               /* Program ISO FIFO size reg (packet number isn't included) */
-               ov518_reg_w32(ov, 0x30, size, 2);
-
-               if (ov->packet_numbering)
-                       ++ov->packet_size;
-       }
-
-       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-               err("Set packet size: set interface error");
-               return -EBUSY;
-       }
-
-       /* Initialize the stream */
-       if (reg_w(ov, 0x2f, 0x80) < 0)
-               return -EIO;
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov511_init_compression(struct usb_ov511 *ov)
-{
-       int rc = 0;
-
-       if (!ov->compress_inited) {
-               reg_w(ov, 0x70, phy);
-               reg_w(ov, 0x71, phuv);
-               reg_w(ov, 0x72, pvy);
-               reg_w(ov, 0x73, pvuv);
-               reg_w(ov, 0x74, qhy);
-               reg_w(ov, 0x75, qhuv);
-               reg_w(ov, 0x76, qvy);
-               reg_w(ov, 0x77, qvuv);
-
-               if (ov511_upload_quan_tables(ov) < 0) {
-                       err("Error uploading quantization tables");
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-
-       ov->compress_inited = 1;
-out:
-       return rc;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov518_init_compression(struct usb_ov511 *ov)
-{
-       int rc = 0;
-
-       if (!ov->compress_inited) {
-               if (ov518_upload_quan_tables(ov) < 0) {
-                       err("Error uploading quantization tables");
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-
-       ov->compress_inited = 1;
-out:
-       return rc;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's contrast setting to "val" */
-static int
-sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       {
-               rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_OV6630:
-       {
-               rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_OV7620:
-       {
-               unsigned char ctab[] = {
-                       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
-                       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-               };
-
-               /* Use Y gamma control instead. Bit 0 enables it. */
-               rc = i2c_w(ov, 0x64, ctab[val>>12]);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_SAA7111A:
-       {
-               rc = i2c_w(ov, 0x0b, val >> 9);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       default:
-       {
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-       }
-
-       rc = 0;         /* Success */
-       ov->contrast = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's contrast setting */
-static int
-sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-               rc = i2c_r(ov, OV7610_REG_CNT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_CNT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 12;
-               break;
-       case SEN_OV7620:
-               /* Use Y gamma reg instead. Bit 0 is the enable bit. */
-               rc = i2c_r(ov, 0x64);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = (rc & 0xfe) << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->contrast;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->contrast = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's brightness setting to "val" */
-static int
-sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(4, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-               /* 7620 doesn't like manual changes when in auto mode */
-               if (!ov->auto_brt) {
-                       rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-                       if (rc < 0)
-                               goto out;
-               }
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0a, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->brightness = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's brightness setting */
-static int
-sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV7620:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_BRT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->brightness;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->brightness = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's saturation (color intensity) setting to "val" */
-static int
-sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-//             /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-//             rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
-//             if (rc < 0)
-//                     goto out;
-               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0c, val >> 9);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->colour = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's saturation (color intensity) setting */
-static int
-sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_SAT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV7620:
-//             /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-//             rc = i2c_r(ov, 0x62);
-//             if (rc < 0)
-//                     return rc;
-//             else
-//                     *val = (rc & 0x7e) << 9;
-               rc = i2c_r(ov, OV7610_REG_SAT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->colour;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->colour = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's hue (red/blue balance) setting to "val" */
-static int
-sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
-               if (rc < 0)
-                       goto out;
-
-               rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-// Hue control is causing problems. I will enable it once it's fixed.
-#if 0
-               rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
-               if (rc < 0)
-                       goto out;
-
-               rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
-               if (rc < 0)
-                       goto out;
-#endif
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->hue = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's hue (red/blue balance) setting */
-static int
-sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_BLUE);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV7620:
-               rc = i2c_r(ov, 0x7a);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->hue;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->hue = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static int
-sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-       int rc;
-
-       PDEBUG(4, "sensor_set_picture");
-
-       ov->whiteness = p->whiteness;
-
-       /* Don't return error if a setting is unsupported, or rest of settings
-        * will not be performed */
-
-       rc = sensor_set_contrast(ov, p->contrast);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_brightness(ov, p->brightness);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_saturation(ov, p->colour);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_hue(ov, p->hue);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       return 0;
-}
-
-static int
-sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-       int rc;
-
-       PDEBUG(4, "sensor_get_picture");
-
-       /* Don't return error if a setting is unsupported, or rest of settings
-        * will not be performed */
-
-       rc = sensor_get_contrast(ov, &(p->contrast));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_brightness(ov, &(p->brightness));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_saturation(ov, &(p->colour));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_hue(ov, &(p->hue));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       p->whiteness = 105 << 8;
-
-       return 0;
-}
-
-#if 0
-// FIXME: Exposure range is only 0x00-0x7f in interlace mode
-/* Sets current exposure for sensor. This only has an effect if auto-exposure
- * is off */
-static inline int
-sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               rc = i2c_w(ov, 0x10, val);
-               if (rc < 0)
-                       goto out;
-
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_exposure");
-               return -EINVAL;
-       }
-
-       rc = 0;         /* Success */
-       ov->exposure = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-#endif
-
-/* Gets current exposure level from sensor, regardless of whether it is under
- * manual control. */
-static int
-sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               rc = i2c_r(ov, 0x10);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc;
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               val = NULL;
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for get_exposure");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->exposure = *val;
-
-       return 0;
-}
-
-/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static void
-ov51x_led_control(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->bridge == BRG_OV511PLUS)
-               reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
-       else if (ov->bclass == BCL_OV518)
-               reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
-
-       return;
-}
-
-/* Matches the sensor's internal frame rate to the lighting frequency.
- * Valid frequencies are:
- *     50 - 50Hz, for European and Asian lighting
- *     60 - 60Hz, for American lighting
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_light_freq(struct usb_ov511 *ov, int freq)
-{
-       int sixty;
-
-       PDEBUG(4, "%d Hz", freq);
-
-       if (freq == 60)
-               sixty = 1;
-       else if (freq == 50)
-               sixty = 0;
-       else {
-               err("Invalid light freq (%d Hz)", freq);
-               return -EINVAL;
-       }
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-               i2c_w(ov, 0x2b, sixty?0x00:0xac);
-               i2c_w_mask(ov, 0x13, 0x10, 0x10);
-               i2c_w_mask(ov, 0x13, 0x00, 0x10);
-               break;
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-               i2c_w(ov, 0x2b, sixty?0x00:0xac);
-               i2c_w_mask(ov, 0x76, 0x01, 0x01);
-               break;
-       case SEN_OV6620:
-       case SEN_OV6630:
-               i2c_w(ov, 0x2b, sixty?0xa8:0x28);
-               i2c_w(ov, 0x2a, sixty?0x84:0xa4);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_light_freq");
-               return -EINVAL;
-       }
-
-       ov->lightfreq = freq;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's banding filter, otherwise turn it
- * off. This filter tries to reduce the pattern of horizontal light/dark bands
- * caused by some (usually fluorescent) lighting. The light frequency must be
- * set either before or after enabling it with ov51x_set_light_freq().
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620.
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
-{
-       int rc;
-
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-               || ov->sensor == SEN_SAA7111A) {
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
-       if (rc < 0)
-               return rc;
-
-       ov->bandfilt = enable;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's auto brightness control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
-{
-       int rc;
-
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-               || ov->sensor == SEN_SAA7111A) {
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
-       if (rc < 0)
-               return rc;
-
-       ov->auto_brt = enable;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's auto exposure control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
-               break;
-       case SEN_OV6620:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
-               break;
-       case SEN_OV6630:
-               i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_auto_exposure");
-               return -EINVAL;
-       }
-
-       ov->auto_exp = enable;
-
-       return 0;
-}
-
-/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
- * that are illuminated from behind.
- *
- * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_backlight(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV7620:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-               break;
-       case SEN_OV6620:
-               i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
-               break;
-       case SEN_OV6630:
-               i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-               break;
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_backlight");
-               return -EINVAL;
-       }
-
-       ov->backlight = enable;
-
-       return 0;
-}
-
-static int
-sensor_set_mirror(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_mirror");
-               return -EINVAL;
-       }
-
-       ov->mirror = enable;
-
-       return 0;
-}
-
-/* Returns number of bits per pixel (regardless of where they are located;
- * planar or not), or zero for unsupported format.
- */
-static inline int
-get_depth(int palette)
-{
-       switch (palette) {
-       case VIDEO_PALETTE_GREY:    return 8;
-       case VIDEO_PALETTE_YUV420:  return 12;
-       case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
-       default:                    return 0;  /* Invalid format */
-       }
-}
-
-/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
-get_frame_length(struct ov511_frame *frame)
-{
-       if (!frame)
-               return 0;
-       else
-               return ((frame->width * frame->height
-                        * get_depth(frame->format)) >> 3);
-}
-
-static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
-                        int mode, int sub_flag, int qvga)
-{
-       int clock;
-
-       /******** Mode (VGA/QVGA) and sensor specific regs ********/
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w(ov, 0x14, qvga?0x24:0x04);
-// FIXME: Does this improve the image quality or frame rate?
-#if 0
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, 0x10);
-               i2c_w(ov, 0x25, qvga?0x40:0x8a);
-               i2c_w(ov, 0x2f, qvga?0x30:0xb0);
-               i2c_w(ov, 0x35, qvga?0x1c:0x9c);
-#endif
-               break;
-       case SEN_OV7620:
-//             i2c_w(ov, 0x2b, 0x00);
-               i2c_w(ov, 0x14, qvga?0xa4:0x84);
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, qvga?0x20:0x3a);
-               i2c_w(ov, 0x25, qvga?0x30:0x60);
-               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-               i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
-               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-               break;
-       case SEN_OV76BE:
-//             i2c_w(ov, 0x2b, 0x00);
-               i2c_w(ov, 0x14, qvga?0xa4:0x84);
-// FIXME: Enable this once 7620AE uses 7620 initial settings
-#if 0
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, qvga?0x20:0x3a);
-               i2c_w(ov, 0x25, qvga?0x30:0x60);
-               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-               i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
-               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-#endif
-               break;
-       case SEN_OV6620:
-               i2c_w(ov, 0x14, qvga?0x24:0x04);
-               break;
-       case SEN_OV6630:
-               i2c_w(ov, 0x14, qvga?0xa0:0x80);
-               break;
-       default:
-               err("Invalid sensor");
-               return -EINVAL;
-       }
-
-       /******** Palette-specific regs ********/
-
-       if (mode == VIDEO_PALETTE_GREY) {
-               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-                       /* these aren't valid on the OV6620/OV7620/6630? */
-                       i2c_w_mask(ov, 0x0e, 0x40, 0x40);
-               }
-
-               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-                   && ov518_color) {
-                       i2c_w_mask(ov, 0x12, 0x00, 0x10);
-                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
-               } else {
-                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
-               }
-       } else {
-               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-                       /* not valid on the OV6620/OV7620/6630? */
-                       i2c_w_mask(ov, 0x0e, 0x00, 0x40);
-               }
-
-               /* The OV518 needs special treatment. Although both the OV518
-                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-                * bus is actually used. The UV bus is tied to ground.
-                * Therefore, the OV6630 needs to be in 8-bit multiplexed
-                * output mode */
-
-               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-                   && ov518_color) {
-                       i2c_w_mask(ov, 0x12, 0x10, 0x10);
-                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
-               } else {
-                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
-               }
-       }
-
-       /******** Clock programming ********/
-
-       /* The OV6620 needs special handling. This prevents the
-        * severe banding that normally occurs */
-       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
-       {
-               /* Clock down */
-
-               i2c_w(ov, 0x2a, 0x04);
-
-               if (ov->compress) {
-//                     clock = 0;    /* This ensures the highest frame rate */
-                       clock = 3;
-               } else if (clockdiv == -1) {   /* If user didn't override it */
-                       clock = 3;    /* Gives better exposure time */
-               } else {
-                       clock = clockdiv;
-               }
-
-               PDEBUG(4, "Setting clock divisor to %d", clock);
-
-               i2c_w(ov, 0x11, clock);
-
-               i2c_w(ov, 0x2a, 0x84);
-               /* This next setting is critical. It seems to improve
-                * the gain or the contrast. The "reserved" bits seem
-                * to have some effect in this case. */
-               i2c_w(ov, 0x2d, 0x85);
-       }
-       else
-       {
-               if (ov->compress) {
-                       clock = 1;    /* This ensures the highest frame rate */
-               } else if (clockdiv == -1) {   /* If user didn't override it */
-                       /* Calculate and set the clock divisor */
-                       clock = ((sub_flag ? ov->subw * ov->subh
-                                 : width * height)
-                                * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
-                                / 66000;
-               } else {
-                       clock = clockdiv;
-               }
-
-               PDEBUG(4, "Setting clock divisor to %d", clock);
-
-               i2c_w(ov, 0x11, clock);
-       }
-
-       /******** Special Features ********/
-
-       if (framedrop >= 0)
-               i2c_w(ov, 0x16, framedrop);
-
-       /* Test Pattern */
-       i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
-
-       /* Enable auto white balance */
-       i2c_w_mask(ov, 0x12, 0x04, 0x04);
-
-       // This will go away as soon as ov51x_mode_init_sensor_regs()
-       // is fully tested.
-       /* 7620/6620/6630? don't have register 0x35, so play it safe */
-       if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-               if (width == 640 && height == 480)
-                       i2c_w(ov, 0x35, 0x9e);
-               else
-                       i2c_w(ov, 0x35, 0x1e);
-       }
-
-       return 0;
-}
-
-static int
-set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
-                    int sub_flag)
-{
-       int ret;
-       int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize;
-       int hoffset, voffset, hwscale = 0, vwscale = 0;
-
-       /* The different sensor ICs handle setting up of window differently.
-        * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-               hwsbase = 0x38;
-               hwebase = 0x3a;
-               vwsbase = vwebase = 0x05;
-               break;
-       case SEN_OV6620:
-       case SEN_OV6630:
-               hwsbase = 0x38;
-               hwebase = 0x3a;
-               vwsbase = 0x05;
-               vwebase = 0x06;
-               break;
-       case SEN_OV7620:
-               hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
-               hwebase = 0x2f;
-               vwsbase = vwebase = 0x05;
-               break;
-       default:
-               err("Invalid sensor");
-               return -EINVAL;
-       }
-
-       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
-               /* Note: OV518(+) does downsample on its own) */
-               if ((width > 176 && height > 144)
-                   || ov->bclass == BCL_OV518) {  /* CIF */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 0);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 1;
-                       vwscale = 1;  /* The datasheet says 0; it's wrong */
-                       hwsize = 352;
-                       vwsize = 288;
-               } else if (width > 176 || height > 144) {
-                       err("Illegal dimensions");
-                       return -EINVAL;
-               } else {                            /* QCIF */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 1);
-                       if (ret < 0)
-                               return ret;
-                       hwsize = 176;
-                       vwsize = 144;
-               }
-       } else {
-               if (width > 320 && height > 240) {  /* VGA */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 0);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 2;
-                       vwscale = 1;
-                       hwsize = 640;
-                       vwsize = 480;
-               } else if (width > 320 || height > 240) {
-                       err("Illegal dimensions");
-                       return -EINVAL;
-               } else {                            /* QVGA */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 1);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 1;
-                       hwsize = 320;
-                       vwsize = 240;
-               }
-       }
-
-       /* Center the window */
-       hoffset = ((hwsize - width) / 2) >> hwscale;
-       voffset = ((vwsize - height) / 2) >> vwscale;
-
-       /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
-       if (sub_flag) {
-               i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
-               i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
-               i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
-               i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
-       } else {
-               i2c_w(ov, 0x17, hwsbase + hoffset);
-               i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
-               i2c_w(ov, 0x19, vwsbase + voffset);
-               i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
-       }
-
-#ifdef OV511_DEBUG
-       if (dump_sensor)
-               dump_i2c_regs(ov);
-#endif
-
-       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)
- */
-static int
-ov511_mode_init_regs(struct usb_ov511 *ov,
-                    int width, int height, int mode, int sub_flag)
-{
-       int hsegs, vsegs;
-
-       if (sub_flag) {
-               width = ov->subw;
-               height = ov->subh;
-       }
-
-       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-              width, height, mode, sub_flag);
-
-       // FIXME: This should be moved to a 7111a-specific function once
-       // subcapture is dealt with properly
-       if (ov->sensor == SEN_SAA7111A) {
-               if (width == 320 && height == 240) {
-                       /* No need to do anything special */
-               } else if (width == 640 && height == 480) {
-                       /* Set the OV511 up as 320x480, but keep the
-                        * V4L resolution as 640x480 */
-                       width = 320;
-               } else {
-                       err("SAA7111A only allows 320x240 or 640x480");
-                       return -EINVAL;
-               }
-       }
-
-       /* Make sure width and height are a multiple of 8 */
-       if (width % 8 || height % 8) {
-               err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
-               return -EINVAL;
-       }
-
-       if (width < ov->minwidth || height < ov->minheight) {
-               err("Requested dimensions are too small");
-               return -EINVAL;
-       }
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       if (mode == VIDEO_PALETTE_GREY) {
-               reg_w(ov, R511_CAM_UV_EN, 0x00);
-               reg_w(ov, R511_SNAP_UV_EN, 0x00);
-               reg_w(ov, R511_SNAP_OPTS, 0x01);
-       } else {
-               reg_w(ov, R511_CAM_UV_EN, 0x01);
-               reg_w(ov, R511_SNAP_UV_EN, 0x01);
-               reg_w(ov, R511_SNAP_OPTS, 0x03);
-       }
-
-       /* Here I'm assuming that snapshot size == image size.
-        * I hope that's always true. --claudio
-        */
-       hsegs = (width >> 3) - 1;
-       vsegs = (height >> 3) - 1;
-
-       reg_w(ov, R511_CAM_PXCNT, hsegs);
-       reg_w(ov, R511_CAM_LNCNT, vsegs);
-       reg_w(ov, R511_CAM_PXDIV, 0x00);
-       reg_w(ov, R511_CAM_LNDIV, 0x00);
-
-       /* YUV420, low pass filter on */
-       reg_w(ov, R511_CAM_OPTS, 0x03);
-
-       /* Snapshot additions */
-       reg_w(ov, R511_SNAP_PXCNT, hsegs);
-       reg_w(ov, R511_SNAP_LNCNT, vsegs);
-       reg_w(ov, R511_SNAP_PXDIV, 0x00);
-       reg_w(ov, R511_SNAP_LNDIV, 0x00);
-
-       if (ov->compress) {
-               /* Enable Y and UV quantization and compression */
-               reg_w(ov, R511_COMP_EN, 0x07);
-               reg_w(ov, R511_COMP_LUT_EN, 0x03);
-               ov51x_reset(ov, OV511_RESET_OMNICE);
-       }
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Sets up the OV518/OV518+ with the given image parameters
- *
- * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Also, only 15 FPS is supported now.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov518_mode_init_regs(struct usb_ov511 *ov,
-                    int width, int height, int mode, int sub_flag)
-{
-       int hsegs, vsegs, hi_res;
-
-       if (sub_flag) {
-               width = ov->subw;
-               height = ov->subh;
-       }
-
-       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-              width, height, mode, sub_flag);
-
-       if (width % 16 || height % 8) {
-               err("Invalid size (%d, %d)", width, height);
-               return -EINVAL;
-       }
-
-       if (width < ov->minwidth || height < ov->minheight) {
-               err("Requested dimensions are too small");
-               return -EINVAL;
-       }
-
-       if (width >= 320 && height >= 240) {
-               hi_res = 1;
-       } else if (width >= 320 || height >= 240) {
-               err("Invalid width/height combination (%d, %d)", width, height);
-               return -EINVAL;
-       } else {
-               hi_res = 0;
-       }
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       /******** Set the mode ********/
-
-       reg_w(ov, 0x2b, 0);
-       reg_w(ov, 0x2c, 0);
-       reg_w(ov, 0x2d, 0);
-       reg_w(ov, 0x2e, 0);
-       reg_w(ov, 0x3b, 0);
-       reg_w(ov, 0x3c, 0);
-       reg_w(ov, 0x3d, 0);
-       reg_w(ov, 0x3e, 0);
-
-       if (ov->bridge == BRG_OV518 && ov518_color) {
-               /* OV518 needs U and V swapped */
-               i2c_w_mask(ov, 0x15, 0x00, 0x01);
-
-               if (mode == VIDEO_PALETTE_GREY) {
-                       /* Set 16-bit input format (UV data are ignored) */
-                       reg_w_mask(ov, 0x20, 0x00, 0x08);
-
-                       /* Set 8-bit (4:0:0) output format */
-                       reg_w_mask(ov, 0x28, 0x00, 0xf0);
-                       reg_w_mask(ov, 0x38, 0x00, 0xf0);
-               } else {
-                       /* Set 8-bit (YVYU) input format */
-                       reg_w_mask(ov, 0x20, 0x08, 0x08);
-
-                       /* Set 12-bit (4:2:0) output format */
-                       reg_w_mask(ov, 0x28, 0x80, 0xf0);
-                       reg_w_mask(ov, 0x38, 0x80, 0xf0);
-               }
-       } else {
-               reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-               reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-       }
-
-       hsegs = width / 16;
-       vsegs = height / 4;
-
-       reg_w(ov, 0x29, hsegs);
-       reg_w(ov, 0x2a, vsegs);
-
-       reg_w(ov, 0x39, hsegs);
-       reg_w(ov, 0x3a, vsegs);
-
-       /* Windows driver does this here; who knows why */
-       reg_w(ov, 0x2f, 0x80);
-
-       /******** Set the framerate (to 15 FPS) ********/
-
-       /* Mode independent, but framerate dependent, regs */
-       reg_w(ov, 0x51, 0x02);  /* Clock divider; lower==faster */
-       reg_w(ov, 0x22, 0x18);
-       reg_w(ov, 0x23, 0xff);
-
-       if (ov->bridge == BRG_OV518PLUS)
-               reg_w(ov, 0x21, 0x19);
-       else
-               reg_w(ov, 0x71, 0x19);  /* Compression-related? */
-
-       // FIXME: Sensor-specific
-       /* Bit 5 is what matters here. Of course, it is "reserved" */
-       i2c_w(ov, 0x54, 0x23);
-
-       reg_w(ov, 0x2f, 0x80);
-
-       if (ov->bridge == BRG_OV518PLUS) {
-               reg_w(ov, 0x24, 0x94);
-               reg_w(ov, 0x25, 0x90);
-               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
-               ov518_reg_w32(ov, 0xc6,    540, 2);     /* 21ch   */
-               ov518_reg_w32(ov, 0xc7,    540, 2);     /* 21ch   */
-               ov518_reg_w32(ov, 0xc8,    108, 2);     /* 6ch    */
-               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
-               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
-               ov518_reg_w32(ov, 0xcc,   2400, 2);     /* 960h   */
-               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
-               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
-       } else {
-               reg_w(ov, 0x24, 0x9f);
-               reg_w(ov, 0x25, 0x90);
-               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
-               ov518_reg_w32(ov, 0xc6,    500, 2);     /* 1f4h   */
-               ov518_reg_w32(ov, 0xc7,    500, 2);     /* 1f4h   */
-               ov518_reg_w32(ov, 0xc8,    142, 2);     /* 8eh    */
-               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
-               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
-               ov518_reg_w32(ov, 0xcc,   2000, 2);     /* 7d0h   */
-               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
-               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
-       }
-
-       reg_w(ov, 0x2f, 0x80);
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       /* Reset it just for good measure */
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* This is a wrapper around the OV511, OV518, and sensor specific functions */
-static int
-mode_init_regs(struct usb_ov511 *ov,
-              int width, int height, int mode, int sub_flag)
-{
-       int rc = 0;
-
-       if (!ov || !ov->dev)
-               return -EFAULT;
-
-       if (ov->bclass == BCL_OV518) {
-               rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
-       } else {
-               rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
-       }
-
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-               err("KS0127-series decoders not supported yet");
-               rc = -EINVAL;
-               break;
-       case SEN_SAA7111A:
-//             rc = mode_init_saa_sensor_regs(ov, width, height, mode,
-//                                            sub_flag);
-
-               PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
-               break;
-       default:
-               err("Unknown sensor");
-               rc = -EINVAL;
-       }
-
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       /* Sensor-independent settings */
-       rc = sensor_set_auto_brightness(ov, ov->auto_brt);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_auto_exposure(ov, ov->auto_exp);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_banding_filter(ov, bandingfilter);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       if (ov->lightfreq) {
-               rc = sensor_set_light_freq(ov, lightfreq);
-               if (FATAL_ERROR(rc))
-                       return rc;
-       }
-
-       rc = sensor_set_backlight(ov, ov->backlight);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_mirror(ov, ov->mirror);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       return 0;
-}
-
-/* This sets the default image parameters. This is useful for apps that use
- * read() and do not set these.
- */
-static int
-ov51x_set_default_params(struct usb_ov511 *ov)
-{
-       int i;
-
-       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
-        * (using read() instead). */
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].width = ov->maxwidth;
-               ov->frame[i].height = ov->maxheight;
-               ov->frame[i].bytes_read = 0;
-               if (force_palette)
-                       ov->frame[i].format = force_palette;
-               else
-                       ov->frame[i].format = VIDEO_PALETTE_YUV420;
-
-               ov->frame[i].depth = get_depth(ov->frame[i].format);
-       }
-
-       PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
-              symbolic(v4l1_plist, ov->frame[0].format));
-
-       /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
-       if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
-                          ov->frame[0].format, 0) < 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-/**********************************************************************
- *
- * Video decoder stuff
- *
- **********************************************************************/
-
-/* Set analog input port of decoder */
-static int
-decoder_set_input(struct usb_ov511 *ov, int input)
-{
-       PDEBUG(4, "port %d", input);
-
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               /* Select mode */
-               i2c_w_mask(ov, 0x02, input, 0x07);
-               /* Bypass chrominance trap for modes 4..7 */
-               i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Get ASCII name of video input */
-static int
-decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
-{
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               if (input < 0 || input > 7)
-                       return -EINVAL;
-               else if (input < 4)
-                       sprintf(name, "CVBS-%d", input);
-               else // if (input < 8)
-                       sprintf(name, "S-Video-%d", input - 4);
-               break;
-       }
-       default:
-               sprintf(name, "%s", "Camera");
-       }
-
-       return 0;
-}
-
-/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
-decoder_set_norm(struct usb_ov511 *ov, int norm)
-{
-       PDEBUG(4, "%d", norm);
-
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               int reg_8, reg_e;
-
-               if (norm == VIDEO_MODE_NTSC) {
-                       reg_8 = 0x40;   /* 60 Hz */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_PAL) {
-                       reg_8 = 0x00;   /* 50 Hz */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_AUTO) {
-                       reg_8 = 0x80;   /* Auto field detect */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_SECAM) {
-                       reg_8 = 0x00;   /* 50 Hz */
-                       reg_e = 0x50;   /* SECAM / PAL 4.43 */
-               } else {
-                       return -EINVAL;
-               }
-
-               i2c_w_mask(ov, 0x08, reg_8, 0xc0);
-               i2c_w_mask(ov, 0x0e, reg_e, 0x70);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**********************************************************************
- *
- * Raw data parsing
- *
- **********************************************************************/
-
-/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * image at pOut is specified by w.
- */
-static inline void
-make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
-{
-       unsigned char *pOut1 = pOut;
-       int x, y;
-
-       for (y = 0; y < 8; y++) {
-               pOut1 = pOut;
-               for (x = 0; x < 8; x++) {
-                       *pOut1++ = *pIn++;
-               }
-               pOut += w;
-       }
-}
-
-/*
- * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
- * The segments represent 4 squares of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127        248 249 ... 255
- *
- */
-static void
-yuv400raw_to_yuv400p(struct ov511_frame *frame,
-                    unsigned char *pIn0, unsigned char *pOut0)
-{
-       int x, y;
-       unsigned char *pIn, *pOut, *pOutLine;
-
-       /* Copy Y */
-       pIn = pIn0;
-       pOutLine = pOut0;
-       for (y = 0; y < frame->rawheight - 1; y += 8) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 8) {
-                       make_8x8(pIn, pOut, frame->rawwidth);
-                       pIn += 64;
-                       pOut += 8;
-               }
-               pOutLine += 8 * frame->rawwidth;
-       }
-}
-
-/*
- * For YUV 4:2:0 images, the data show up in 384 byte segments.
- * The first 64 bytes of each segment are U, the next 64 are V.  The U and
- * V are arranged as follows:
- *
- *      0  1 ...  7
- *      8  9 ... 15
- *           ...
- *     56 57 ... 63
- *
- * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
- *
- * The next 256 bytes are full resolution Y data and represent 4 squares
- * of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
- *
- * Note that the U and V data in one segment represent a 16 x 16 pixel
- * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
- * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
- * next horizontal stripe.
- *
- * If dumppix module param is set, _parse_data just dumps the incoming segments,
- * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
- * this puts the data on the standard output and can be analyzed with the
- * parseppm.c utility I wrote.  That's a much faster way for figuring out how
- * these data are scrambled.
- */
-
-/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
- *
- * FIXME: Currently only handles width and height that are multiples of 16
- */
-static void
-yuv420raw_to_yuv420p(struct ov511_frame *frame,
-                    unsigned char *pIn0, unsigned char *pOut0)
-{
-       int k, x, y;
-       unsigned char *pIn, *pOut, *pOutLine;
-       const unsigned int a = frame->rawwidth * frame->rawheight;
-       const unsigned int w = frame->rawwidth / 2;
-
-       /* Copy U and V */
-       pIn = pIn0;
-       pOutLine = pOut0 + a;
-       for (y = 0; y < frame->rawheight - 1; y += 16) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 16) {
-                       make_8x8(pIn, pOut, w);
-                       make_8x8(pIn + 64, pOut + a/4, w);
-                       pIn += 384;
-                       pOut += 8;
-               }
-               pOutLine += 8 * w;
-       }
-
-       /* Copy Y */
-       pIn = pIn0 + 128;
-       pOutLine = pOut0;
-       k = 0;
-       for (y = 0; y < frame->rawheight - 1; y += 8) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 8) {
-                       make_8x8(pIn, pOut, frame->rawwidth);
-                       pIn += 64;
-                       pOut += 8;
-                       if ((++k) > 3) {
-                               k = 0;
-                               pIn += 128;
-                       }
-               }
-               pOutLine += 8 * frame->rawwidth;
-       }
-}
-
-/**********************************************************************
- *
- * Decompression
- *
- **********************************************************************/
-
-static int
-request_decompressor(struct usb_ov511 *ov)
-{
-       if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
-               err("No decompressor available");
-       } else {
-               err("Unknown bridge");
-       }
-
-       return -ENOSYS;
-}
-
-static void
-decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
-          unsigned char *pIn0, unsigned char *pOut0)
-{
-       if (!ov->decomp_ops)
-               if (request_decompressor(ov))
-                       return;
-
-}
-
-/**********************************************************************
- *
- * Format conversion
- *
- **********************************************************************/
-
-/* Fuses even and odd fields together, and doubles width.
- * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
- * OUTPUT: a normal YUV planar image, with correct aspect ratio
- */
-static void
-deinterlace(struct ov511_frame *frame, int rawformat,
-           unsigned char *pIn0, unsigned char *pOut0)
-{
-       const int fieldheight = frame->rawheight / 2;
-       const int fieldpix = fieldheight * frame->rawwidth;
-       const int w = frame->width;
-       int x, y;
-       unsigned char *pInEven, *pInOdd, *pOut;
-
-       PDEBUG(5, "fieldheight=%d", fieldheight);
-
-       if (frame->rawheight != frame->height) {
-               err("invalid height");
-               return;
-       }
-
-       if ((frame->rawwidth * 2) != frame->width) {
-               err("invalid width");
-               return;
-       }
-
-       /* Y */
-       pInOdd = pIn0;
-       pInEven = pInOdd + fieldpix;
-       pOut = pOut0;
-       for (y = 0; y < fieldheight; y++) {
-               for (x = 0; x < frame->rawwidth; x++) {
-                       *pOut = *pInEven;
-                       *(pOut+1) = *pInEven++;
-                       *(pOut+w) = *pInOdd;
-                       *(pOut+w+1) = *pInOdd++;
-                       pOut += 2;
-               }
-               pOut += w;
-       }
-
-       if (rawformat == RAWFMT_YUV420) {
-       /* U */
-               pInOdd = pIn0 + fieldpix * 2;
-               pInEven = pInOdd + fieldpix / 4;
-               for (y = 0; y < fieldheight / 2; y++) {
-                       for (x = 0; x < frame->rawwidth / 2; x++) {
-                               *pOut = *pInEven;
-                               *(pOut+1) = *pInEven++;
-                               *(pOut+w/2) = *pInOdd;
-                               *(pOut+w/2+1) = *pInOdd++;
-                               pOut += 2;
-                       }
-                       pOut += w/2;
-               }
-       /* V */
-               pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
-               pInEven = pInOdd + fieldpix / 4;
-               for (y = 0; y < fieldheight / 2; y++) {
-                       for (x = 0; x < frame->rawwidth / 2; x++) {
-                               *pOut = *pInEven;
-                               *(pOut+1) = *pInEven++;
-                               *(pOut+w/2) = *pInOdd;
-                               *(pOut+w/2+1) = *pInOdd++;
-                               pOut += 2;
-                       }
-                       pOut += w/2;
-               }
-       }
-}
-
-static void
-ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-               /* Deinterlace frame, if necessary */
-               if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-                       if (frame->compressed)
-                               decompress(ov, frame, frame->rawdata,
-                                                frame->tempdata);
-                       else
-                               yuv400raw_to_yuv400p(frame, frame->rawdata,
-                                                    frame->tempdata);
-
-                       deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
-                                   frame->data);
-               } else {
-                       if (frame->compressed)
-                               decompress(ov, frame, frame->rawdata,
-                                                frame->data);
-                       else
-                               yuv400raw_to_yuv400p(frame, frame->rawdata,
-                                                    frame->data);
-               }
-}
-
-/* Process raw YUV420 data into standard YUV420P */
-static void
-ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-       /* Deinterlace frame, if necessary */
-       if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-               if (frame->compressed)
-                       decompress(ov, frame, frame->rawdata, frame->tempdata);
-               else
-                       yuv420raw_to_yuv420p(frame, frame->rawdata,
-                                            frame->tempdata);
-
-               deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
-                           frame->data);
-       } else {
-               if (frame->compressed)
-                       decompress(ov, frame, frame->rawdata, frame->data);
-               else
-                       yuv420raw_to_yuv420p(frame, frame->rawdata,
-                                            frame->data);
-       }
-}
-
-/* Post-processes the specified frame. This consists of:
- *     1. Decompress frame, if necessary
- *     2. Deinterlace frame and scale to proper size, if necessary
- *     3. Convert from YUV planar to destination format, if necessary
- *     4. Fix the RGB offset, if necessary
- */
-static void
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-       if (dumppix) {
-               memset(frame->data, 0,
-                       MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-               PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-               memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
-       } else {
-               switch (frame->format) {
-               case VIDEO_PALETTE_GREY:
-                       ov51x_postprocess_grey(ov, frame);
-                       break;
-               case VIDEO_PALETTE_YUV420:
-               case VIDEO_PALETTE_YUV420P:
-                       ov51x_postprocess_yuv420(ov, frame);
-                       break;
-               default:
-                       err("Cannot convert data to %s",
-                           symbolic(v4l1_plist, frame->format));
-               }
-       }
-}
-
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static inline void
-ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-       int num, offset;
-       int pnum = in[ov->packet_size - 1];             /* Get packet number */
-       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-       struct ov511_frame *frame = &ov->frame[ov->curframe];
-       struct timeval *ts;
-
-       /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-        * byte non-zero. The EOF packet has image width/height in the
-        * 10th and 11th bytes. The 9th byte is given as follows:
-        *
-        * bit 7: EOF
-        *     6: compression enabled
-        *     5: 422/420/400 modes
-        *     4: 422/420/400 modes
-        *     3: 1
-        *     2: snapshot button on
-        *     1: snapshot frame
-        *     0: even/odd field
-        */
-
-       if (printph) {
-               dev_info(&ov->dev->dev,
-                        "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
-                        pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
-                        in[7], in[8], in[9], in[10], in[11]);
-       }
-
-       /* Check for SOF/EOF packet */
-       if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
-           (~in[8] & 0x08))
-               goto check_middle;
-
-       /* Frame end */
-       if (in[8] & 0x80) {
-               ts = (struct timeval *)(frame->data
-                     + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-               do_gettimeofday(ts);
-
-               /* Get the actual frame size from the EOF header */
-               frame->rawwidth = ((int)(in[9]) + 1) * 8;
-               frame->rawheight = ((int)(in[10]) + 1) * 8;
-
-               PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
-                       ov->curframe, pnum, frame->rawwidth, frame->rawheight,
-                       frame->bytes_recvd);
-
-               /* Validate the header data */
-               RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-               RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
-                                 ov->maxheight);
-
-               /* Don't allow byte count to exceed buffer size */
-               RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-               if (frame->scanstate == STATE_LINES) {
-                       int nextf;
-
-                       frame->grabstate = FRAME_DONE;
-                       wake_up_interruptible(&frame->wq);
-
-                       /* If next frame is ready or grabbing,
-                        * point to it */
-                       nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-                       if (ov->frame[nextf].grabstate == FRAME_READY
-                           || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-                               ov->curframe = nextf;
-                               ov->frame[nextf].scanstate = STATE_SCANNING;
-                       } else {
-                               if (frame->grabstate == FRAME_DONE) {
-                                       PDEBUG(4, "** Frame done **");
-                               } else {
-                                       PDEBUG(4, "Frame not ready? state = %d",
-                                               ov->frame[nextf].grabstate);
-                               }
-
-                               ov->curframe = -1;
-                       }
-               } else {
-                       PDEBUG(5, "Frame done, but not scanning");
-               }
-               /* Image corruption caused by misplaced frame->segment = 0
-                * fixed by carlosf@conectiva.com.br
-                */
-       } else {
-               /* Frame start */
-               PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
-               /* Check to see if it's a snapshot frame */
-               /* FIXME?? Should the snapshot reset go here? Performance? */
-               if (in[8] & 0x02) {
-                       frame->snapshot = 1;
-                       PDEBUG(3, "snapshot detected");
-               }
-
-               frame->scanstate = STATE_LINES;
-               frame->bytes_recvd = 0;
-               frame->compressed = in[8] & 0x40;
-       }
-
-check_middle:
-       /* Are we in a frame? */
-       if (frame->scanstate != STATE_LINES) {
-               PDEBUG(5, "Not in a frame; packet skipped");
-               return;
-       }
-
-       /* If frame start, skip header */
-       if (frame->bytes_recvd == 0)
-               offset = 9;
-       else
-               offset = 0;
-
-       num = n - offset - 1;
-
-       /* Dump all data exactly as received */
-       if (dumppix == 2) {
-               frame->bytes_recvd += n - 1;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
-                               in, n - 1);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else if (!frame->compressed && !remove_zeros) {
-               frame->bytes_recvd += num;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - num,
-                               in + offset, num);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-               int b, read = 0, allzero, copied = 0;
-               if (offset) {
-                       frame->bytes_recvd += 32 - offset;      // Bytes out
-                       memcpy(frame->rawdata,  in + offset, 32 - offset);
-                       read += 32;
-               }
-
-               while (read < n - 1) {
-                       allzero = 1;
-                       for (b = 0; b < 32; b++) {
-                               if (in[read + b]) {
-                                       allzero = 0;
-                                       break;
-                               }
-                       }
-
-                       if (allzero) {
-                               /* Don't copy it */
-                       } else {
-                               if (frame->bytes_recvd + copied + 32 <= max_raw)
-                               {
-                                       memcpy(frame->rawdata
-                                               + frame->bytes_recvd + copied,
-                                               in + read, 32);
-                                       copied += 32;
-                               } else {
-                                       PDEBUG(3, "Raw data buffer overrun!!");
-                               }
-                       }
-                       read += 32;
-               }
-
-               frame->bytes_recvd += copied;
-       }
-}
-
-static inline void
-ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-       struct ov511_frame *frame = &ov->frame[ov->curframe];
-       struct timeval *ts;
-
-       /* Don't copy the packet number byte */
-       if (ov->packet_numbering)
-               --n;
-
-       /* A false positive here is likely, until OVT gives me
-        * the definitive SOF/EOF format */
-       if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
-               if (printph) {
-                       dev_info(&ov->dev->dev,
-                                "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n",
-                                in[0], in[1], in[2], in[3], in[4], in[5],
-                                in[6], in[7]);
-               }
-
-               if (frame->scanstate == STATE_LINES) {
-                       PDEBUG(4, "Detected frame end/start");
-                       goto eof;
-               } else { //scanstate == STATE_SCANNING
-                       /* Frame start */
-                       PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-                       goto sof;
-               }
-       } else {
-               goto check_middle;
-       }
-
-eof:
-       ts = (struct timeval *)(frame->data
-             + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-       do_gettimeofday(ts);
-
-       PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-               ov->curframe,
-               (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
-
-       // FIXME: Since we don't know the header formats yet,
-       // there is no way to know what the actual image size is
-       frame->rawwidth = frame->width;
-       frame->rawheight = frame->height;
-
-       /* Validate the header data */
-       RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-       RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-       /* Don't allow byte count to exceed buffer size */
-       RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-       if (frame->scanstate == STATE_LINES) {
-               int nextf;
-
-               frame->grabstate = FRAME_DONE;
-               wake_up_interruptible(&frame->wq);
-
-               /* If next frame is ready or grabbing,
-                * point to it */
-               nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-               if (ov->frame[nextf].grabstate == FRAME_READY
-                   || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-                       ov->curframe = nextf;
-                       ov->frame[nextf].scanstate = STATE_SCANNING;
-                       frame = &ov->frame[nextf];
-               } else {
-                       if (frame->grabstate == FRAME_DONE) {
-                               PDEBUG(4, "** Frame done **");
-                       } else {
-                               PDEBUG(4, "Frame not ready? state = %d",
-                                      ov->frame[nextf].grabstate);
-                       }
-
-                       ov->curframe = -1;
-                       PDEBUG(4, "SOF dropped (no active frame)");
-                       return;  /* Nowhere to store this frame */
-               }
-       }
-sof:
-       PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-
-// Snapshot not reverse-engineered yet.
-#if 0
-       /* Check to see if it's a snapshot frame */
-       /* FIXME?? Should the snapshot reset go here? Performance? */
-       if (in[8] & 0x02) {
-               frame->snapshot = 1;
-               PDEBUG(3, "snapshot detected");
-       }
-#endif
-       frame->scanstate = STATE_LINES;
-       frame->bytes_recvd = 0;
-       frame->compressed = 1;
-
-check_middle:
-       /* Are we in a frame? */
-       if (frame->scanstate != STATE_LINES) {
-               PDEBUG(4, "scanstate: no SOF yet");
-               return;
-       }
-
-       /* Dump all data exactly as received */
-       if (dumppix == 2) {
-               frame->bytes_recvd += n;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else {
-               /* All incoming data are divided into 8-byte segments. If the
-                * segment contains all zero bytes, it must be skipped. These
-                * zero-segments allow the OV518 to mainain a constant data rate
-                * regardless of the effectiveness of the compression. Segments
-                * are aligned relative to the beginning of each isochronous
-                * packet. The first segment in each image is a header (the
-                * decompressor skips it later).
-                */
-
-               int b, read = 0, allzero, copied = 0;
-
-               while (read < n) {
-                       allzero = 1;
-                       for (b = 0; b < 8; b++) {
-                               if (in[read + b]) {
-                                       allzero = 0;
-                                       break;
-                               }
-                       }
-
-                       if (allzero) {
-                       /* Don't copy it */
-                       } else {
-                               if (frame->bytes_recvd + copied + 8 <= max_raw)
-                               {
-                                       memcpy(frame->rawdata
-                                               + frame->bytes_recvd + copied,
-                                               in + read, 8);
-                                       copied += 8;
-                               } else {
-                                       PDEBUG(3, "Raw data buffer overrun!!");
-                               }
-                       }
-                       read += 8;
-               }
-               frame->bytes_recvd += copied;
-       }
-}
-
-static void
-ov51x_isoc_irq(struct urb *urb)
-{
-       int i;
-       struct usb_ov511 *ov;
-       struct ov511_sbuf *sbuf;
-
-       if (!urb->context) {
-               PDEBUG(4, "no context");
-               return;
-       }
-
-       sbuf = urb->context;
-       ov = sbuf->ov;
-
-       if (!ov || !ov->dev || !ov->user) {
-               PDEBUG(4, "no device, or not open");
-               return;
-       }
-
-       if (!ov->streaming) {
-               PDEBUG(4, "hmmm... not streaming, but got interrupt");
-               return;
-       }
-
-       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-               PDEBUG(4, "URB unlinked");
-               return;
-       }
-
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
-               err("ERROR: urb->status=%d: %s", urb->status,
-                   symbolic(urb_errlist, urb->status));
-       }
-
-       /* Copy the data received into our frame buffer */
-       PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
-              urb->number_of_packets);
-       for (i = 0; i < urb->number_of_packets; i++) {
-               /* Warning: Don't call *_move_data() if no frame active! */
-               if (ov->curframe >= 0) {
-                       int n = urb->iso_frame_desc[i].actual_length;
-                       int st = urb->iso_frame_desc[i].status;
-                       unsigned char *cdata;
-
-                       urb->iso_frame_desc[i].actual_length = 0;
-                       urb->iso_frame_desc[i].status = 0;
-
-                       cdata = urb->transfer_buffer
-                               + urb->iso_frame_desc[i].offset;
-
-                       if (!n) {
-                               PDEBUG(4, "Zero-length packet");
-                               continue;
-                       }
-
-                       if (st)
-                               PDEBUG(2, "data error: [%d] len=%d, status=%d",
-                                      i, n, st);
-
-                       if (ov->bclass == BCL_OV511)
-                               ov511_move_data(ov, cdata, n);
-                       else if (ov->bclass == BCL_OV518)
-                               ov518_move_data(ov, cdata, n);
-                       else
-                               err("Unknown bridge device (%d)", ov->bridge);
-
-               } else if (waitqueue_active(&ov->wq)) {
-                       wake_up_interruptible(&ov->wq);
-               }
-       }
-
-       /* Resubmit this URB */
-       urb->dev = ov->dev;
-       if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
-               err("usb_submit_urb() ret %d", i);
-
-       return;
-}
-
-/****************************************************************************
- *
- * Stream initialization and termination
- *
- ***************************************************************************/
-
-static int
-ov51x_init_isoc(struct usb_ov511 *ov)
-{
-       struct urb *urb;
-       int fx, err, n, i, size;
-
-       PDEBUG(3, "*** Initializing capture ***");
-
-       ov->curframe = -1;
-
-       if (ov->bridge == BRG_OV511) {
-               if (cams == 1)
-                       size = 993;
-               else if (cams == 2)
-                       size = 513;
-               else if (cams == 3 || cams == 4)
-                       size = 257;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (cams == 1)
-                       size = 961;
-               else if (cams == 2)
-                       size = 513;
-               else if (cams == 3 || cams == 4)
-                       size = 257;
-               else if (cams >= 5 && cams <= 8)
-                       size = 129;
-               else if (cams >= 9 && cams <= 31)
-                       size = 33;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               if (cams == 1)
-                       size = 896;
-               else if (cams == 2)
-                       size = 512;
-               else if (cams == 3 || cams == 4)
-                       size = 256;
-               else if (cams >= 5 && cams <= 8)
-                       size = 128;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else {
-               err("invalid bridge type");
-               return -1;
-       }
-
-       // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-       if (ov->bclass == BCL_OV518) {
-               if (packetsize == -1) {
-                       ov518_set_packet_size(ov, 640);
-               } else {
-                       dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
-                                packetsize);
-                       ov518_set_packet_size(ov, packetsize);
-               }
-       } else {
-               if (packetsize == -1) {
-                       ov511_set_packet_size(ov, size);
-               } else {
-                       dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
-                                packetsize);
-                       ov511_set_packet_size(ov, packetsize);
-               }
-       }
-
-       for (n = 0; n < OV511_NUMSBUF; n++) {
-               urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-               if (!urb) {
-                       err("init isoc: usb_alloc_urb ret. NULL");
-                       for (i = 0; i < n; i++)
-                               usb_free_urb(ov->sbuf[i].urb);
-                       return -ENOMEM;
-               }
-               ov->sbuf[n].urb = urb;
-               urb->dev = ov->dev;
-               urb->context = &ov->sbuf[n];
-               urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = ov->sbuf[n].data;
-               urb->complete = ov51x_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
-               urb->interval = 1;
-               for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-                       urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
-                       urb->iso_frame_desc[fx].length = ov->packet_size;
-               }
-       }
-
-       ov->streaming = 1;
-
-       for (n = 0; n < OV511_NUMSBUF; n++) {
-               ov->sbuf[n].urb->dev = ov->dev;
-               err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
-               if (err) {
-                       err("init isoc: usb_submit_urb(%d) ret %d", n, err);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static void
-ov51x_unlink_isoc(struct usb_ov511 *ov)
-{
-       int n;
-
-       /* Unschedule all of the iso td's */
-       for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-               if (ov->sbuf[n].urb) {
-                       usb_kill_urb(ov->sbuf[n].urb);
-                       usb_free_urb(ov->sbuf[n].urb);
-                       ov->sbuf[n].urb = NULL;
-               }
-       }
-}
-
-static void
-ov51x_stop_isoc(struct usb_ov511 *ov)
-{
-       if (!ov->streaming || !ov->dev)
-               return;
-
-       PDEBUG(3, "*** Stopping capture ***");
-
-       if (ov->bclass == BCL_OV518)
-               ov518_set_packet_size(ov, 0);
-       else
-               ov511_set_packet_size(ov, 0);
-
-       ov->streaming = 0;
-
-       ov51x_unlink_isoc(ov);
-}
-
-static int
-ov51x_new_frame(struct usb_ov511 *ov, int framenum)
-{
-       struct ov511_frame *frame;
-       int newnum;
-
-       PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
-
-       if (!ov->dev)
-               return -1;
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /* ready to be grabbed into, then use it instead */
-       if (ov->curframe == -1) {
-               newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
-               if (ov->frame[newnum].grabstate == FRAME_READY)
-                       framenum = newnum;
-       } else
-               return 0;
-
-       frame = &ov->frame[framenum];
-
-       PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
-              frame->width, frame->height);
-
-       frame->grabstate = FRAME_GRABBING;
-       frame->scanstate = STATE_SCANNING;
-       frame->snapshot = 0;
-
-       ov->curframe = framenum;
-
-       /* Make sure it's not too big */
-       if (frame->width > ov->maxwidth)
-               frame->width = ov->maxwidth;
-
-       frame->width &= ~7L;            /* Multiple of 8 */
-
-       if (frame->height > ov->maxheight)
-               frame->height = ov->maxheight;
-
-       frame->height &= ~3L;           /* Multiple of 4 */
-
-       return 0;
-}
-
-/****************************************************************************
- *
- * Buffer management
- *
- ***************************************************************************/
-
-/*
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
-       int i;
-       PDEBUG(4, "entered");
-
-       if (ov->fbuf) {
-               rvfree(ov->fbuf, OV511_NUMFRAMES
-                      * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-               ov->fbuf = NULL;
-       }
-
-       vfree(ov->rawfbuf);
-       ov->rawfbuf = NULL;
-
-       vfree(ov->tempfbuf);
-       ov->tempfbuf = NULL;
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               kfree(ov->sbuf[i].data);
-               ov->sbuf[i].data = NULL;
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].data = NULL;
-               ov->frame[i].rawdata = NULL;
-               ov->frame[i].tempdata = NULL;
-               if (ov->frame[i].compbuf) {
-                       free_page((unsigned long) ov->frame[i].compbuf);
-                       ov->frame[i].compbuf = NULL;
-               }
-       }
-
-       PDEBUG(4, "buffer memory deallocated");
-       ov->buf_state = BUF_NOT_ALLOCATED;
-       PDEBUG(4, "leaving");
-}
-
-static int
-ov51x_alloc(struct usb_ov511 *ov)
-{
-       int i;
-       const int w = ov->maxwidth;
-       const int h = ov->maxheight;
-       const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
-       const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
-       PDEBUG(4, "entered");
-       mutex_lock(&ov->buf_lock);
-
-       if (ov->buf_state == BUF_ALLOCATED)
-               goto out;
-
-       ov->fbuf = rvmalloc(data_bufsize);
-       if (!ov->fbuf)
-               goto error;
-
-       ov->rawfbuf = vmalloc(raw_bufsize);
-       if (!ov->rawfbuf)
-               goto error;
-
-       memset(ov->rawfbuf, 0, raw_bufsize);
-
-       ov->tempfbuf = vmalloc(raw_bufsize);
-       if (!ov->tempfbuf)
-               goto error;
-
-       memset(ov->tempfbuf, 0, raw_bufsize);
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
-                       MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-               if (!ov->sbuf[i].data)
-                       goto error;
-
-               PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
-               ov->frame[i].rawdata = ov->rawfbuf
-                + i * MAX_RAW_DATA_SIZE(w, h);
-               ov->frame[i].tempdata = ov->tempfbuf
-                + i * MAX_RAW_DATA_SIZE(w, h);
-
-               ov->frame[i].compbuf =
-                (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!ov->frame[i].compbuf)
-                       goto error;
-
-               PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
-       }
-
-       ov->buf_state = BUF_ALLOCATED;
-out:
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "leaving");
-       return 0;
-error:
-       ov51x_do_dealloc(ov);
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "errored");
-       return -ENOMEM;
-}
-
-static void
-ov51x_dealloc(struct usb_ov511 *ov)
-{
-       PDEBUG(4, "entered");
-       mutex_lock(&ov->buf_lock);
-       ov51x_do_dealloc(ov);
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "leaving");
-}
-
-/****************************************************************************
- *
- * V4L 1 API
- *
- ***************************************************************************/
-
-static int
-ov51x_v4l1_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int err, i;
-
-       PDEBUG(4, "opening");
-
-       mutex_lock(&ov->lock);
-
-       err = -EBUSY;
-       if (ov->user)
-               goto out;
-
-       ov->sub_flag = 0;
-
-       /* In case app doesn't set them... */
-       err = ov51x_set_default_params(ov);
-       if (err < 0)
-               goto out;
-
-       /* Make sure frames are reset */
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].grabstate = FRAME_UNUSED;
-               ov->frame[i].bytes_read = 0;
-       }
-
-       /* If compression is on, make sure now that a
-        * decompressor can be loaded */
-       if (ov->compress && !ov->decomp_ops) {
-               err = request_decompressor(ov);
-               if (err && !dumppix)
-                       goto out;
-       }
-
-       err = ov51x_alloc(ov);
-       if (err < 0)
-               goto out;
-
-       err = ov51x_init_isoc(ov);
-       if (err) {
-               ov51x_dealloc(ov);
-               goto out;
-       }
-
-       ov->user++;
-       file->private_data = vdev;
-
-       if (ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 1);
-
-out:
-       mutex_unlock(&ov->lock);
-       return err;
-}
-
-static int
-ov51x_v4l1_close(struct file *file)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-
-       PDEBUG(4, "ov511_close");
-
-       mutex_lock(&ov->lock);
-
-       ov->user--;
-       ov51x_stop_isoc(ov);
-
-       if (ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-
-       if (ov->dev)
-               ov51x_dealloc(ov);
-
-       mutex_unlock(&ov->lock);
-
-       /* Device unplugged while open. Only a minimum of unregistration is done
-        * here; the disconnect callback already did the rest. */
-       if (!ov->dev) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-
-               ov51x_dealloc(ov);
-               kfree(ov);
-               ov = NULL;
-       }
-
-       file->private_data = NULL;
-       return 0;
-}
-
-/* Do not call this function directly! */
-static long
-ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       PDEBUG(5, "IOCtl: 0x%X", cmd);
-
-       if (!ov->dev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *b = arg;
-
-               PDEBUG(4, "VIDIOCGCAP");
-
-               memset(b, 0, sizeof(struct video_capability));
-               sprintf(b->name, "%s USB Camera",
-                       symbolic(brglist, ov->bridge));
-               b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-               b->channels = ov->num_inputs;
-               b->audios = 0;
-               b->maxwidth = ov->maxwidth;
-               b->maxheight = ov->maxheight;
-               b->minwidth = ov->minwidth;
-               b->minheight = ov->minheight;
-
-               return 0;
-       }
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-
-               PDEBUG(4, "VIDIOCGCHAN");
-
-               if ((unsigned)(v->channel) >= ov->num_inputs) {
-                       err("Invalid channel (%d)", v->channel);
-                       return -EINVAL;
-               }
-
-               v->norm = ov->norm;
-               v->type = VIDEO_TYPE_CAMERA;
-               v->flags = 0;
-//             v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-               v->tuners = 0;
-               decoder_get_input_name(ov, v->channel, v->name);
-
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-               int err;
-
-               PDEBUG(4, "VIDIOCSCHAN");
-
-               /* Make sure it's not a camera */
-               if (!ov->has_decoder) {
-                       if (v->channel == 0)
-                               return 0;
-                       else
-                               return -EINVAL;
-               }
-
-               if (v->norm != VIDEO_MODE_PAL &&
-                   v->norm != VIDEO_MODE_NTSC &&
-                   v->norm != VIDEO_MODE_SECAM &&
-                   v->norm != VIDEO_MODE_AUTO) {
-                       err("Invalid norm (%d)", v->norm);
-                       return -EINVAL;
-               }
-
-               if ((unsigned)(v->channel) >= ov->num_inputs) {
-                       err("Invalid channel (%d)", v->channel);
-                       return -EINVAL;
-               }
-
-               err = decoder_set_input(ov, v->channel);
-               if (err)
-                       return err;
-
-               err = decoder_set_norm(ov, v->norm);
-               if (err)
-                       return err;
-
-               return 0;
-       }
-       case VIDIOCGPICT:
-       {
-               struct video_picture *p = arg;
-
-               PDEBUG(4, "VIDIOCGPICT");
-
-               memset(p, 0, sizeof(struct video_picture));
-               if (sensor_get_picture(ov, p))
-                       return -EIO;
-
-               /* Can we get these from frame[0]? -claudio? */
-               p->depth = ov->frame[0].depth;
-               p->palette = ov->frame[0].format;
-
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *p = arg;
-               int i, rc;
-
-               PDEBUG(4, "VIDIOCSPICT");
-
-               if (!get_depth(p->palette))
-                       return -EINVAL;
-
-               if (sensor_set_picture(ov, p))
-                       return -EIO;
-
-               if (force_palette && p->palette != force_palette) {
-                       dev_info(&ov->dev->dev, "Palette rejected (%s)\n",
-                            symbolic(v4l1_plist, p->palette));
-                       return -EINVAL;
-               }
-
-               // FIXME: Format should be independent of frames
-               if (p->palette != ov->frame[0].format) {
-                       PDEBUG(4, "Detected format change");
-
-                       rc = ov51x_wait_frames_inactive(ov);
-                       if (rc)
-                               return rc;
-
-                       mode_init_regs(ov, ov->frame[0].width,
-                               ov->frame[0].height, p->palette, ov->sub_flag);
-               }
-
-               PDEBUG(4, "Setting depth=%d, palette=%s",
-                      p->depth, symbolic(v4l1_plist, p->palette));
-
-               for (i = 0; i < OV511_NUMFRAMES; i++) {
-                       ov->frame[i].depth = p->depth;
-                       ov->frame[i].format = p->palette;
-               }
-
-               return 0;
-       }
-       case VIDIOCGCAPTURE:
-       {
-               int *vf = arg;
-
-               PDEBUG(4, "VIDIOCGCAPTURE");
-
-               ov->sub_flag = *vf;
-               return 0;
-       }
-       case VIDIOCSCAPTURE:
-       {
-               struct video_capture *vc = arg;
-
-               PDEBUG(4, "VIDIOCSCAPTURE");
-
-               if (vc->flags)
-                       return -EINVAL;
-               if (vc->decimation)
-                       return -EINVAL;
-
-               vc->x &= ~3L;
-               vc->y &= ~1L;
-               vc->y &= ~31L;
-
-               if (vc->width == 0)
-                       vc->width = 32;
-
-               vc->height /= 16;
-               vc->height *= 16;
-               if (vc->height == 0)
-                       vc->height = 16;
-
-               ov->subx = vc->x;
-               ov->suby = vc->y;
-               ov->subw = vc->width;
-               ov->subh = vc->height;
-
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *vw = arg;
-               int i, rc;
-
-               PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
-
-#if 0
-               if (vw->flags)
-                       return -EINVAL;
-               if (vw->clipcount)
-                       return -EINVAL;
-               if (vw->height != ov->maxheight)
-                       return -EINVAL;
-               if (vw->width != ov->maxwidth)
-                       return -EINVAL;
-#endif
-
-               rc = ov51x_wait_frames_inactive(ov);
-               if (rc)
-                       return rc;
-
-               rc = mode_init_regs(ov, vw->width, vw->height,
-                       ov->frame[0].format, ov->sub_flag);
-               if (rc < 0)
-                       return rc;
-
-               for (i = 0; i < OV511_NUMFRAMES; i++) {
-                       ov->frame[i].width = vw->width;
-                       ov->frame[i].height = vw->height;
-               }
-
-               return 0;
-       }
-       case VIDIOCGWIN:
-       {
-               struct video_window *vw = arg;
-
-               memset(vw, 0, sizeof(struct video_window));
-               vw->x = 0;              /* FIXME */
-               vw->y = 0;
-               vw->width = ov->frame[0].width;
-               vw->height = ov->frame[0].height;
-               vw->flags = 30;
-
-               PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
-
-               return 0;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vm = arg;
-               int i;
-
-               PDEBUG(4, "VIDIOCGMBUF");
-
-               memset(vm, 0, sizeof(struct video_mbuf));
-               vm->size = OV511_NUMFRAMES
-                          * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-               vm->frames = OV511_NUMFRAMES;
-
-               vm->offsets[0] = 0;
-               for (i = 1; i < OV511_NUMFRAMES; i++) {
-                       vm->offsets[i] = vm->offsets[i-1]
-                          + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-               }
-
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-               int rc, depth;
-               unsigned int f = vm->frame;
-
-               PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
-                       vm->height, symbolic(v4l1_plist, vm->format));
-
-               depth = get_depth(vm->format);
-               if (!depth) {
-                       PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
-                              symbolic(v4l1_plist, vm->format));
-                       return -EINVAL;
-               }
-
-               if (f >= OV511_NUMFRAMES) {
-                       err("VIDIOCMCAPTURE: invalid frame (%d)", f);
-                       return -EINVAL;
-               }
-
-               if (vm->width > ov->maxwidth
-                   || vm->height > ov->maxheight) {
-                       err("VIDIOCMCAPTURE: requested dimensions too big");
-                       return -EINVAL;
-               }
-
-               if (ov->frame[f].grabstate == FRAME_GRABBING) {
-                       PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
-                       return -EBUSY;
-               }
-
-               if (force_palette && (vm->format != force_palette)) {
-                       PDEBUG(2, "palette rejected (%s)",
-                              symbolic(v4l1_plist, vm->format));
-                       return -EINVAL;
-               }
-
-               if ((ov->frame[f].width != vm->width) ||
-                   (ov->frame[f].height != vm->height) ||
-                   (ov->frame[f].format != vm->format) ||
-                   (ov->frame[f].sub_flag != ov->sub_flag) ||
-                   (ov->frame[f].depth != depth)) {
-                       PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
-
-                       rc = ov51x_wait_frames_inactive(ov);
-                       if (rc)
-                               return rc;
-
-                       rc = mode_init_regs(ov, vm->width, vm->height,
-                               vm->format, ov->sub_flag);
-#if 0
-                       if (rc < 0) {
-                               PDEBUG(1, "Got error while initializing regs ");
-                               return ret;
-                       }
-#endif
-                       ov->frame[f].width = vm->width;
-                       ov->frame[f].height = vm->height;
-                       ov->frame[f].format = vm->format;
-                       ov->frame[f].sub_flag = ov->sub_flag;
-                       ov->frame[f].depth = depth;
-               }
-
-               /* Mark it as ready */
-               ov->frame[f].grabstate = FRAME_READY;
-
-               PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
-
-               return ov51x_new_frame(ov, f);
-       }
-       case VIDIOCSYNC:
-       {
-               unsigned int fnum = *((unsigned int *) arg);
-               struct ov511_frame *frame;
-               int rc;
-
-               if (fnum >= OV511_NUMFRAMES) {
-                       err("VIDIOCSYNC: invalid frame (%d)", fnum);
-                       return -EINVAL;
-               }
-
-               frame = &ov->frame[fnum];
-
-               PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
-                      frame->grabstate);
-
-               switch (frame->grabstate) {
-               case FRAME_UNUSED:
-                       return -EINVAL;
-               case FRAME_READY:
-               case FRAME_GRABBING:
-               case FRAME_ERROR:
-redo:
-                       if (!ov->dev)
-                               return -EIO;
-
-                       rc = wait_event_interruptible(frame->wq,
-                           (frame->grabstate == FRAME_DONE)
-                           || (frame->grabstate == FRAME_ERROR));
-
-                       if (rc)
-                               return rc;
-
-                       if (frame->grabstate == FRAME_ERROR) {
-                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-                                       return rc;
-                               goto redo;
-                       }
-                       /* Fall through */
-               case FRAME_DONE:
-                       if (ov->snap_enabled && !frame->snapshot) {
-                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-                                       return rc;
-                               goto redo;
-                       }
-
-                       frame->grabstate = FRAME_UNUSED;
-
-                       /* Reset the hardware snapshot button */
-                       /* FIXME - Is this the best place for this? */
-                       if ((ov->snap_enabled) && (frame->snapshot)) {
-                               frame->snapshot = 0;
-                               ov51x_clear_snapshot(ov);
-                       }
-
-                       /* Decompression, format conversion, etc... */
-                       ov51x_postprocess(ov, frame);
-
-                       break;
-               } /* end switch */
-
-               return 0;
-       }
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vb = arg;
-
-               PDEBUG(4, "VIDIOCGFBUF");
-
-               memset(vb, 0, sizeof(struct video_buffer));
-
-               return 0;
-       }
-       case VIDIOCGUNIT:
-       {
-               struct video_unit *vu = arg;
-
-               PDEBUG(4, "VIDIOCGUNIT");
-
-               memset(vu, 0, sizeof(struct video_unit));
-
-               vu->video = ov->vdev->minor;
-               vu->vbi = VIDEO_NO_UNIT;
-               vu->radio = VIDEO_NO_UNIT;
-               vu->audio = VIDEO_NO_UNIT;
-               vu->teletext = VIDEO_NO_UNIT;
-
-               return 0;
-       }
-       case OV511IOC_WI2C:
-       {
-               struct ov511_i2c_struct *w = arg;
-
-               return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
-       }
-       case OV511IOC_RI2C:
-       {
-               struct ov511_i2c_struct *r = arg;
-               int rc;
-
-               rc = i2c_r_slave(ov, r->slave, r->reg);
-               if (rc < 0)
-                       return rc;
-
-               r->value = rc;
-               return 0;
-       }
-       default:
-               PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-               return -ENOIOCTLCMD;
-       } /* end switch */
-
-       return 0;
-}
-
-static long
-ov51x_v4l1_ioctl(struct file *file,
-                unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int rc;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       rc = video_usercopy(file, cmd, arg, ov51x_v4l1_ioctl_internal);
-
-       mutex_unlock(&ov->lock);
-       return rc;
-}
-
-static ssize_t
-ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
-{
-       struct video_device *vdev = file->private_data;
-       int noblock = file->f_flags&O_NONBLOCK;
-       unsigned long count = cnt;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int i, rc = 0, frmx = -1;
-       struct ov511_frame *frame;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
-
-       if (!vdev || !buf) {
-               rc = -EFAULT;
-               goto error;
-       }
-
-       if (!ov->dev) {
-               rc = -EIO;
-               goto error;
-       }
-
-// FIXME: Only supports two frames
-       /* See if a frame is completed, then use it. */
-       if (ov->frame[0].grabstate >= FRAME_DONE)       /* _DONE or _ERROR */
-               frmx = 0;
-       else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-               frmx = 1;
-
-       /* If nonblocking we return immediately */
-       if (noblock && (frmx == -1)) {
-               rc = -EAGAIN;
-               goto error;
-       }
-
-       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
-       /* See if a frame is in process (grabbing), then use it. */
-       if (frmx == -1) {
-               if (ov->frame[0].grabstate == FRAME_GRABBING)
-                       frmx = 0;
-               else if (ov->frame[1].grabstate == FRAME_GRABBING)
-                       frmx = 1;
-       }
-
-       /* If no frame is active, start one. */
-       if (frmx == -1) {
-               if ((rc = ov51x_new_frame(ov, frmx = 0))) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-       }
-
-       frame = &ov->frame[frmx];
-
-restart:
-       if (!ov->dev) {
-               rc = -EIO;
-               goto error;
-       }
-
-       /* Wait while we're grabbing the image */
-       PDEBUG(4, "Waiting image grabbing");
-       rc = wait_event_interruptible(frame->wq,
-               (frame->grabstate == FRAME_DONE)
-               || (frame->grabstate == FRAME_ERROR));
-
-       if (rc)
-               goto error;
-
-       PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
-       PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
-
-       if (frame->grabstate == FRAME_ERROR) {
-               frame->bytes_read = 0;
-               err("** ick! ** Errored frame %d", ov->curframe);
-               if (ov51x_new_frame(ov, frmx)) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-               goto restart;
-       }
-
-
-       /* Repeat until we get a snapshot frame */
-       if (ov->snap_enabled)
-               PDEBUG(4, "Waiting snapshot frame");
-       if (ov->snap_enabled && !frame->snapshot) {
-               frame->bytes_read = 0;
-               if ((rc = ov51x_new_frame(ov, frmx))) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-               goto restart;
-       }
-
-       /* Clear the snapshot */
-       if (ov->snap_enabled && frame->snapshot) {
-               frame->snapshot = 0;
-               ov51x_clear_snapshot(ov);
-       }
-
-       /* Decompression, format conversion, etc... */
-       ov51x_postprocess(ov, frame);
-
-       PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
-               frame->bytes_read,
-               get_frame_length(frame));
-
-       /* copy bytes to user space; we allow for partials reads */
-//     if ((count + frame->bytes_read)
-//         > get_frame_length((struct ov511_frame *)frame))
-//             count = frame->scanlength - frame->bytes_read;
-
-       /* FIXME - count hardwired to be one frame... */
-       count = get_frame_length(frame);
-
-       PDEBUG(4, "Copy to user space: %ld bytes", count);
-       if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
-               PDEBUG(4, "Copy failed! %d bytes not copied", i);
-               rc = -EFAULT;
-               goto error;
-       }
-
-       frame->bytes_read += count;
-       PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
-               count, frame->bytes_read);
-
-       /* If all data have been read... */
-       if (frame->bytes_read
-           >= get_frame_length(frame)) {
-               frame->bytes_read = 0;
-
-// FIXME: Only supports two frames
-               /* Mark it as available to be used again. */
-               ov->frame[frmx].grabstate = FRAME_UNUSED;
-               if ((rc = ov51x_new_frame(ov, !frmx))) {
-                       err("ov51x_new_frame returned error");
-                       goto error;
-               }
-       }
-
-       PDEBUG(4, "read finished, returning %ld (sweet)", count);
-
-       mutex_unlock(&ov->lock);
-       return count;
-
-error:
-       mutex_unlock(&ov->lock);
-       return rc;
-}
-
-static int
-ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *vdev = file->private_data;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end - vma->vm_start;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       unsigned long page, pos;
-
-       if (ov->dev == NULL)
-               return -EIO;
-
-       PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
-
-       if (size > (((OV511_NUMFRAMES
-                     * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
-                     + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       pos = (unsigned long)ov->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&ov->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       mutex_unlock(&ov->lock);
-       return 0;
-}
-
-static const struct v4l2_file_operations ov511_fops = {
-       .owner =        THIS_MODULE,
-       .open =         ov51x_v4l1_open,
-       .release =      ov51x_v4l1_close,
-       .read =         ov51x_v4l1_read,
-       .mmap =         ov51x_v4l1_mmap,
-       .ioctl =        ov51x_v4l1_ioctl,
-};
-
-static struct video_device vdev_template = {
-       .name =         "OV511 USB Camera",
-       .fops =         &ov511_fops,
-       .release =      video_device_release,
-};
-
-/****************************************************************************
- *
- * OV511 and sensor configuration
- *
- ***************************************************************************/
-
-/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
- * the same register settings as the OV7610, since they are very similar.
- */
-static int
-ov7xx0_configure(struct usb_ov511 *ov)
-{
-       int i, success;
-       int rc;
-
-       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
-        *
-        * Register 0x0f in the 7610 has the following effects:
-        *
-        * 0x85 (AEC method 1): Best overall, good contrast range
-        * 0x45 (AEC method 2): Very overexposed
-        * 0xa5 (spec sheet default): Ok, but the black level is
-        *      shifted resulting in loss of contrast
-        * 0x05 (old driver setting): very overexposed, too much
-        *      contrast
-        */
-       static struct ov511_regvals aRegvalsNorm7610[] = {
-               { OV511_I2C_BUS, 0x10, 0xff },
-               { OV511_I2C_BUS, 0x16, 0x06 },
-               { OV511_I2C_BUS, 0x28, 0x24 },
-               { OV511_I2C_BUS, 0x2b, 0xac },
-               { OV511_I2C_BUS, 0x12, 0x00 },
-               { OV511_I2C_BUS, 0x38, 0x81 },
-               { OV511_I2C_BUS, 0x28, 0x24 },  /* 0c */
-               { OV511_I2C_BUS, 0x0f, 0x85 },  /* lg's setting */
-               { OV511_I2C_BUS, 0x15, 0x01 },
-               { OV511_I2C_BUS, 0x20, 0x1c },
-               { OV511_I2C_BUS, 0x23, 0x2a },
-               { OV511_I2C_BUS, 0x24, 0x10 },
-               { OV511_I2C_BUS, 0x25, 0x8a },
-               { OV511_I2C_BUS, 0x26, 0xa2 },
-               { OV511_I2C_BUS, 0x27, 0xc2 },
-               { OV511_I2C_BUS, 0x2a, 0x04 },
-               { OV511_I2C_BUS, 0x2c, 0xfe },
-               { OV511_I2C_BUS, 0x2d, 0x93 },
-               { OV511_I2C_BUS, 0x30, 0x71 },
-               { OV511_I2C_BUS, 0x31, 0x60 },
-               { OV511_I2C_BUS, 0x32, 0x26 },
-               { OV511_I2C_BUS, 0x33, 0x20 },
-               { OV511_I2C_BUS, 0x34, 0x48 },
-               { OV511_I2C_BUS, 0x12, 0x24 },
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm7620[] = {
-               { OV511_I2C_BUS, 0x00, 0x00 },
-               { OV511_I2C_BUS, 0x01, 0x80 },
-               { OV511_I2C_BUS, 0x02, 0x80 },
-               { OV511_I2C_BUS, 0x03, 0xc0 },
-               { OV511_I2C_BUS, 0x06, 0x60 },
-               { OV511_I2C_BUS, 0x07, 0x00 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x12, 0x24 },
-               { OV511_I2C_BUS, 0x13, 0x01 },
-               { OV511_I2C_BUS, 0x14, 0x84 },
-               { OV511_I2C_BUS, 0x15, 0x01 },
-               { OV511_I2C_BUS, 0x16, 0x03 },
-               { OV511_I2C_BUS, 0x17, 0x2f },
-               { OV511_I2C_BUS, 0x18, 0xcf },
-               { OV511_I2C_BUS, 0x19, 0x06 },
-               { OV511_I2C_BUS, 0x1a, 0xf5 },
-               { OV511_I2C_BUS, 0x1b, 0x00 },
-               { OV511_I2C_BUS, 0x20, 0x18 },
-               { OV511_I2C_BUS, 0x21, 0x80 },
-               { OV511_I2C_BUS, 0x22, 0x80 },
-               { OV511_I2C_BUS, 0x23, 0x00 },
-               { OV511_I2C_BUS, 0x26, 0xa2 },
-               { OV511_I2C_BUS, 0x27, 0xea },
-               { OV511_I2C_BUS, 0x28, 0x20 },
-               { OV511_I2C_BUS, 0x29, 0x00 },
-               { OV511_I2C_BUS, 0x2a, 0x10 },
-               { OV511_I2C_BUS, 0x2b, 0x00 },
-               { OV511_I2C_BUS, 0x2c, 0x88 },
-               { OV511_I2C_BUS, 0x2d, 0x91 },
-               { OV511_I2C_BUS, 0x2e, 0x80 },
-               { OV511_I2C_BUS, 0x2f, 0x44 },
-               { OV511_I2C_BUS, 0x60, 0x27 },
-               { OV511_I2C_BUS, 0x61, 0x02 },
-               { OV511_I2C_BUS, 0x62, 0x5f },
-               { OV511_I2C_BUS, 0x63, 0xd5 },
-               { OV511_I2C_BUS, 0x64, 0x57 },
-               { OV511_I2C_BUS, 0x65, 0x83 },
-               { OV511_I2C_BUS, 0x66, 0x55 },
-               { OV511_I2C_BUS, 0x67, 0x92 },
-               { OV511_I2C_BUS, 0x68, 0xcf },
-               { OV511_I2C_BUS, 0x69, 0x76 },
-               { OV511_I2C_BUS, 0x6a, 0x22 },
-               { OV511_I2C_BUS, 0x6b, 0x00 },
-               { OV511_I2C_BUS, 0x6c, 0x02 },
-               { OV511_I2C_BUS, 0x6d, 0x44 },
-               { OV511_I2C_BUS, 0x6e, 0x80 },
-               { OV511_I2C_BUS, 0x6f, 0x1d },
-               { OV511_I2C_BUS, 0x70, 0x8b },
-               { OV511_I2C_BUS, 0x71, 0x00 },
-               { OV511_I2C_BUS, 0x72, 0x14 },
-               { OV511_I2C_BUS, 0x73, 0x54 },
-               { OV511_I2C_BUS, 0x74, 0x00 },
-               { OV511_I2C_BUS, 0x75, 0x8e },
-               { OV511_I2C_BUS, 0x76, 0x00 },
-               { OV511_I2C_BUS, 0x77, 0xff },
-               { OV511_I2C_BUS, 0x78, 0x80 },
-               { OV511_I2C_BUS, 0x79, 0x80 },
-               { OV511_I2C_BUS, 0x7a, 0x80 },
-               { OV511_I2C_BUS, 0x7b, 0xe2 },
-               { OV511_I2C_BUS, 0x7c, 0x00 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "starting configuration");
-
-       /* This looks redundant, but is necessary for WebCam 3 */
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               return -1;
-
-       if (init_ov_sensor(ov) >= 0) {
-               PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
-       } else {
-               /* Reset the 76xx */
-               if (i2c_w(ov, 0x12, 0x80) < 0)
-                       return -1;
-
-               /* Wait for it to initialize */
-               msleep(150);
-
-               i = 0;
-               success = 0;
-               while (i <= i2c_detect_tries) {
-                       if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-                           (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-                               success = 1;
-                               break;
-                       } else {
-                               i++;
-                       }
-               }
-
-// Was (i == i2c_detect_tries) previously. This obviously used to always report
-// success. Whether anyone actually depended on that bug is unknown
-               if ((i >= i2c_detect_tries) && (success == 0)) {
-                       err("Failed to read sensor ID. You might not have an");
-                       err("OV7610/20, or it may be not responding. Report");
-                       err("this to " EMAIL);
-                       err("This is only a warning. You can attempt to use");
-                       err("your camera anyway");
-// Only issue a warning for now
-//                     return -1;
-               } else {
-                       PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
-               }
-       }
-
-       /* Detect sensor (sub)type */
-       rc = i2c_r(ov, OV7610_REG_COM_I);
-
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       } else if ((rc & 3) == 3) {
-               dev_info(&ov->dev->dev, "Sensor is an OV7610\n");
-               ov->sensor = SEN_OV7610;
-       } else if ((rc & 3) == 1) {
-               /* I don't know what's different about the 76BE yet. */
-               if (i2c_r(ov, 0x15) & 1)
-                       dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n");
-               else
-                       dev_info(&ov->dev->dev, "Sensor is an OV76BE\n");
-
-               /* OV511+ will return all zero isoc data unless we
-                * configure the sensor as a 7620. Someone needs to
-                * find the exact reg. setting that causes this. */
-               if (ov->bridge == BRG_OV511PLUS) {
-                       dev_info(&ov->dev->dev,
-                                "Enabling 511+/7620AE workaround\n");
-                       ov->sensor = SEN_OV7620;
-               } else {
-                       ov->sensor = SEN_OV76BE;
-               }
-       } else if ((rc & 3) == 0) {
-               dev_info(&ov->dev->dev, "Sensor is an OV7620\n");
-               ov->sensor = SEN_OV7620;
-       } else {
-               err("Unknown image sensor version: %d", rc & 3);
-               return -1;
-       }
-
-       if (ov->sensor == SEN_OV7620) {
-               PDEBUG(4, "Writing 7620 registers");
-               if (write_regvals(ov, aRegvalsNorm7620))
-                       return -1;
-       } else {
-               PDEBUG(4, "Writing 7610 registers");
-               if (write_regvals(ov, aRegvalsNorm7610))
-                       return -1;
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 640;
-       ov->maxheight = 480;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       return 0;
-}
-
-/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
-ov6xx0_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-       static struct ov511_regvals aRegvalsNorm6x20[] = {
-               { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x03, 0x60 },
-               { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-               { OV511_I2C_BUS, 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
-               { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
-               { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
-               { OV511_I2C_BUS, 0x14, 0x04 },
-               /* 0x16: 0x06 helps frame stability with moving objects */
-               { OV511_I2C_BUS, 0x16, 0x06 },
-//             { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-               { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-               { OV511_I2C_BUS, 0x28, 0x05 },
-               { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//             { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-               { OV511_I2C_BUS, 0x2d, 0x99 },
-               { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
-               { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
-               { OV511_I2C_BUS, 0x38, 0x8b },
-               { OV511_I2C_BUS, 0x39, 0x40 },
-
-               { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-               { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-               { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-               { OV511_I2C_BUS, 0x3d, 0x80 },
-               /* These next two registers (0x4a, 0x4b) are undocumented. They
-                * control the color balance */
-               { OV511_I2C_BUS, 0x4a, 0x80 },
-               { OV511_I2C_BUS, 0x4b, 0x80 },
-               { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
-               { OV511_I2C_BUS, 0x4e, 0xc1 },
-               { OV511_I2C_BUS, 0x4f, 0x04 },
-// Do 50-53 have any effect?
-// Toggle 0x12[2] off and on here?
-               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
-       };
-
-       static struct ov511_regvals aRegvalsNorm6x30[] = {
-       /*OK*/  { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-               { OV511_I2C_BUS, 0x11, 0x00 },
-       /*OK*/  { OV511_I2C_BUS, 0x03, 0x60 },
-       /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-               { OV511_I2C_BUS, 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-       /*OK*/  { OV511_I2C_BUS, 0x0c, 0x24 },
-       /*OK*/  { OV511_I2C_BUS, 0x0d, 0x24 },
-       /*A*/   { OV511_I2C_BUS, 0x0e, 0x20 },
-//     /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
-               { OV511_I2C_BUS, 0x16, 0x03 },
-//     /*OK*/  { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-               // 21 & 22? The suggested values look wrong. Go with default
-       /*A*/   { OV511_I2C_BUS, 0x23, 0xc0 },
-       /*A*/   { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-//     /*OK*/  { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
-//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
-
-       /*OK*/  { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//     /*OK*/  { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-               { OV511_I2C_BUS, 0x2d, 0x99 },
-//     /*A*/   { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-//     /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-//     /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
-//     /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
-//             { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-//             { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-//             { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-               { OV511_I2C_BUS, 0x3d, 0x80 },
-//     /*A*/   { OV511_I2C_BUS, 0x3f, 0x0e },
-
-               /* These next two registers (0x4a, 0x4b) are undocumented. They
-                * control the color balance */
-//     /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-//     /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
-               { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-       /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
-
-               /* UV average mode, color killer: strongest */
-               { OV511_I2C_BUS, 0x4f, 0x07 },
-
-               { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
-               { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
-               { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
-               { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
-               { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
-//             { OV511_I2C_BUS, 0x5c, 0x10 },
-               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
-       };
-
-       PDEBUG(4, "starting sensor configuration");
-
-       if (init_ov_sensor(ov) < 0) {
-               err("Failed to read sensor ID. You might not have an OV6xx0,");
-               err("or it may be not responding. Report this to " EMAIL);
-               return -1;
-       } else {
-               PDEBUG(1, "OV6xx0 sensor detected");
-       }
-
-       /* Detect sensor (sub)type */
-       rc = i2c_r(ov, OV7610_REG_COM_I);
-
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       }
-
-       if ((rc & 3) == 0) {
-               ov->sensor = SEN_OV6630;
-               dev_info(&ov->dev->dev, "Sensor is an OV6630\n");
-       } else if ((rc & 3) == 1) {
-               ov->sensor = SEN_OV6620;
-               dev_info(&ov->dev->dev, "Sensor is an OV6620\n");
-       } else if ((rc & 3) == 2) {
-               ov->sensor = SEN_OV6630;
-               dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n");
-       } else if ((rc & 3) == 3) {
-               ov->sensor = SEN_OV6630;
-               dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n");
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 352;
-       ov->maxheight = 288;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       if (ov->sensor == SEN_OV6620) {
-               PDEBUG(4, "Writing 6x20 registers");
-               if (write_regvals(ov, aRegvalsNorm6x20))
-                       return -1;
-       } else {
-               PDEBUG(4, "Writing 6x30 registers");
-               if (write_regvals(ov, aRegvalsNorm6x30))
-                       return -1;
-       }
-
-       return 0;
-}
-
-/* This initializes the KS0127 and KS0127B video decoders. */
-static int
-ks0127_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-       if (ov51x_init_ks_sensor(ov) < 0) {
-               err("Failed to initialize the KS0127");
-               return -1;
-       } else {
-               PDEBUG(1, "KS012x(B) sensor detected");
-       }
-#endif
-
-       /* Detect decoder subtype */
-       rc = i2c_r(ov, 0x00);
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       } else if (rc & 0x08) {
-               rc = i2c_r(ov, 0x3d);
-               if (rc < 0) {
-                       err("Error detecting sensor type");
-                       return -1;
-               } else if ((rc & 0x0f) == 0) {
-                       dev_info(&ov->dev->dev, "Sensor is a KS0127\n");
-                       ov->sensor = SEN_KS0127;
-               } else if ((rc & 0x0f) == 9) {
-                       dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n");
-                       ov->sensor = SEN_KS0127B;
-               }
-       } else {
-               err("Error: Sensor is an unsupported KS0122");
-               return -1;
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 640;
-       ov->maxheight = 480;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       /* This device is not supported yet. Bail out now... */
-       err("This sensor is not supported yet.");
-       return -1;
-
-       return 0;
-}
-
-/* This initializes the SAA7111A video decoder. */
-static int
-saa7111a_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-       /* Since there is no register reset command, all registers must be
-        * written, otherwise gives erratic results */
-       static struct ov511_regvals aRegvalsNormSAA7111A[] = {
-               { OV511_I2C_BUS, 0x06, 0xce },
-               { OV511_I2C_BUS, 0x07, 0x00 },
-               { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
-               { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
-               { OV511_I2C_BUS, 0x00, 0x00 },
-               { OV511_I2C_BUS, 0x01, 0x00 },
-               { OV511_I2C_BUS, 0x03, 0x23 },
-               { OV511_I2C_BUS, 0x04, 0x00 },
-               { OV511_I2C_BUS, 0x05, 0x00 },
-               { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
-               { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
-               { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
-               { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
-               { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
-               { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
-               { OV511_I2C_BUS, 0x0f, 0x00 },
-               { OV511_I2C_BUS, 0x11, 0x0c },
-               { OV511_I2C_BUS, 0x12, 0x00 },
-               { OV511_I2C_BUS, 0x13, 0x00 },
-               { OV511_I2C_BUS, 0x14, 0x00 },
-               { OV511_I2C_BUS, 0x15, 0x00 },
-               { OV511_I2C_BUS, 0x16, 0x00 },
-               { OV511_I2C_BUS, 0x17, 0x00 },
-               { OV511_I2C_BUS, 0x02, 0xc0 },  /* Composite input 0 */
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-       if (ov51x_init_saa_sensor(ov) < 0) {
-               err("Failed to initialize the SAA7111A");
-               return -1;
-       } else {
-               PDEBUG(1, "SAA7111A sensor detected");
-       }
-#endif
-
-       /* 640x480 not supported with PAL */
-       if (ov->pal) {
-               ov->maxwidth = 320;
-               ov->maxheight = 240;            /* Even field only */
-       } else {
-               ov->maxwidth = 640;
-               ov->maxheight = 480;            /* Even/Odd fields */
-       }
-
-       ov->minwidth = 320;
-       ov->minheight = 240;            /* Even field only */
-
-       ov->has_decoder = 1;
-       ov->num_inputs = 8;
-       ov->norm = VIDEO_MODE_AUTO;
-       ov->stop_during_set = 0;        /* Decoder guarantees stable image */
-
-       /* Decoder doesn't change these values, so we use these instead of
-        * acutally reading the registers (which doesn't work) */
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x40 << 9;
-       ov->colour = 0x40 << 9;
-       ov->hue = 32768;
-
-       PDEBUG(4, "Writing SAA7111A registers");
-       if (write_regvals(ov, aRegvalsNormSAA7111A))
-               return -1;
-
-       /* Detect version of decoder. This must be done after writing the
-        * initial regs or the decoder will lock up. */
-       rc = i2c_r(ov, 0x00);
-
-       if (rc < 0) {
-               err("Error detecting sensor version");
-               return -1;
-       } else {
-               dev_info(&ov->dev->dev,
-                        "Sensor is an SAA7111A (version 0x%x)\n", rc);
-               ov->sensor = SEN_SAA7111A;
-       }
-
-       // FIXME: Fix this for OV518(+)
-       /* Latch to negative edge of clock. Otherwise, we get incorrect
-        * colors and jitter in the digital signal. */
-       if (ov->bclass == BCL_OV511)
-               reg_w(ov, 0x11, 0x00);
-       else
-               dev_warn(&ov->dev->dev,
-                        "SAA7111A not yet supported with OV518/OV518+\n");
-
-       return 0;
-}
-
-/* This initializes the OV511/OV511+ and the sensor */
-static int
-ov511_configure(struct usb_ov511 *ov)
-{
-       static struct ov511_regvals aRegvalsInit511[] = {
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3d },
-               { OV511_DONE_BUS, 0x0, 0x00},
-       };
-
-       static struct ov511_regvals aRegvalsNorm511[] = {
-               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0x01 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R511_FIFO_OPTS,        0x1f },
-               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
-               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm511Plus[] = {
-               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0xff },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R511_FIFO_OPTS,        0xff },
-               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
-               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "");
-
-       ov->customid = reg_r(ov, R511_SYS_CUST_ID);
-       if (ov->customid < 0) {
-               err("Unable to read camera bridge registers");
-               goto error;
-       }
-
-       PDEBUG (1, "CustomID = %d", ov->customid);
-       ov->desc = symbolic(camlist, ov->customid);
-       dev_info(&ov->dev->dev, "model: %s\n", ov->desc);
-
-       if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
-               err("Camera type (%d) not recognized", ov->customid);
-               err("Please notify " EMAIL " of the name,");
-               err("manufacturer, model, and this number of your camera.");
-               err("Also include the output of the detection process.");
-       }
-
-       if (ov->customid == 70)         /* USB Life TV (PAL/SECAM) */
-               ov->pal = 1;
-
-       if (write_regvals(ov, aRegvalsInit511))
-               goto error;
-
-       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-
-       /* The OV511+ has undocumented bits in the flow control register.
-        * Setting it to 0xff fixes the corruption with moving objects. */
-       if (ov->bridge == BRG_OV511) {
-               if (write_regvals(ov, aRegvalsNorm511))
-                       goto error;
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (write_regvals(ov, aRegvalsNorm511Plus))
-                       goto error;
-       } else {
-               err("Invalid bridge");
-       }
-
-       if (ov511_init_compression(ov))
-               goto error;
-
-       ov->packet_numbering = 1;
-       ov511_set_packet_size(ov, 0);
-
-       ov->snap_enabled = snapshot;
-
-       /* Test for 7xx0 */
-       PDEBUG(3, "Testing for 0V7xx0");
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               goto error;
-
-       if (i2c_w(ov, 0x12, 0x80) < 0) {
-               /* Test for 6xx0 */
-               PDEBUG(3, "Testing for 0V6xx0");
-               ov->primary_i2c_slave = OV6xx0_SID;
-               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-                       goto error;
-
-               if (i2c_w(ov, 0x12, 0x80) < 0) {
-                       /* Test for 8xx0 */
-                       PDEBUG(3, "Testing for 0V8xx0");
-                       ov->primary_i2c_slave = OV8xx0_SID;
-                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-                               goto error;
-
-                       if (i2c_w(ov, 0x12, 0x80) < 0) {
-                               /* Test for SAA7111A */
-                               PDEBUG(3, "Testing for SAA7111A");
-                               ov->primary_i2c_slave = SAA7111A_SID;
-                               if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
-                                       goto error;
-
-                               if (i2c_w(ov, 0x0d, 0x00) < 0) {
-                                       /* Test for KS0127 */
-                                       PDEBUG(3, "Testing for KS0127");
-                                       ov->primary_i2c_slave = KS0127_SID;
-                                       if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
-                                               goto error;
-
-                                       if (i2c_w(ov, 0x10, 0x00) < 0) {
-                                               err("Can't determine sensor slave IDs");
-                                               goto error;
-                                       } else {
-                                               if (ks0127_configure(ov) < 0) {
-                                                       err("Failed to configure KS0127");
-                                                       goto error;
-                                               }
-                                       }
-                               } else {
-                                       if (saa7111a_configure(ov) < 0) {
-                                               err("Failed to configure SAA7111A");
-                                               goto error;
-                                       }
-                               }
-                       } else {
-                               err("Detected unsupported OV8xx0 sensor");
-                               goto error;
-                       }
-               } else {
-                       if (ov6xx0_configure(ov) < 0) {
-                               err("Failed to configure OV6xx0");
-                               goto error;
-                       }
-               }
-       } else {
-               if (ov7xx0_configure(ov) < 0) {
-                       err("Failed to configure OV7xx0");
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       err("OV511 Config failed");
-
-       return -EBUSY;
-}
-
-/* This initializes the OV518/OV518+ and the sensor */
-static int
-ov518_configure(struct usb_ov511 *ov)
-{
-       /* For 518 and 518+ */
-       static struct ov511_regvals aRegvalsInit518[] = {
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x40 },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3e },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x00 },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, 0x46,                  0x00 },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00},
-       };
-
-       static struct ov511_regvals aRegvalsNorm518[] = {
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
-               { OV511_REG_BUS, 0x31,                  0x0f },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_REG_BUS, 0x24,                  0x9f },
-               { OV511_REG_BUS, 0x25,                  0x90 },
-               { OV511_REG_BUS, 0x20,                  0x00 },
-               { OV511_REG_BUS, 0x51,                  0x04 },
-               { OV511_REG_BUS, 0x71,                  0x19 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm518Plus[] = {
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
-               { OV511_REG_BUS, 0x31,                  0x0f },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_REG_BUS, 0x24,                  0x9f },
-               { OV511_REG_BUS, 0x25,                  0x90 },
-               { OV511_REG_BUS, 0x20,                  0x60 },
-               { OV511_REG_BUS, 0x51,                  0x02 },
-               { OV511_REG_BUS, 0x71,                  0x19 },
-               { OV511_REG_BUS, 0x40,                  0xff },
-               { OV511_REG_BUS, 0x41,                  0x42 },
-               { OV511_REG_BUS, 0x46,                  0x00 },
-               { OV511_REG_BUS, 0x33,                  0x04 },
-               { OV511_REG_BUS, 0x21,                  0x19 },
-               { OV511_REG_BUS, 0x3f,                  0x10 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "");
-
-       /* First 5 bits of custom ID reg are a revision ID on OV518 */
-       dev_info(&ov->dev->dev, "Device revision %d\n",
-                0x1F & reg_r(ov, R511_SYS_CUST_ID));
-
-       /* Give it the default description */
-       ov->desc = symbolic(camlist, 0);
-
-       if (write_regvals(ov, aRegvalsInit518))
-               goto error;
-
-       /* Set LED GPIO pin to output mode */
-       if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
-               goto error;
-
-       /* LED is off by default with OV518; have to explicitly turn it on */
-       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-       else
-               ov51x_led_control(ov, 1);
-
-       /* Don't require compression if dumppix is enabled; otherwise it's
-        * required. OV518 has no uncompressed mode, to save RAM. */
-       if (!dumppix && !ov->compress) {
-               ov->compress = 1;
-               dev_warn(&ov->dev->dev,
-                        "Compression required with OV518...enabling\n");
-       }
-
-       if (ov->bridge == BRG_OV518) {
-               if (write_regvals(ov, aRegvalsNorm518))
-                       goto error;
-       } else if (ov->bridge == BRG_OV518PLUS) {
-               if (write_regvals(ov, aRegvalsNorm518Plus))
-                       goto error;
-       } else {
-               err("Invalid bridge");
-       }
-
-       if (reg_w(ov, 0x2f, 0x80) < 0)
-               goto error;
-
-       if (ov518_init_compression(ov))
-               goto error;
-
-       if (ov->bridge == BRG_OV518)
-       {
-               struct usb_interface *ifp;
-               struct usb_host_interface *alt;
-               __u16 mxps = 0;
-
-               ifp = usb_ifnum_to_if(ov->dev, 0);
-               if (ifp) {
-                       alt = usb_altnum_to_altsetting(ifp, 7);
-                       if (alt)
-                               mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
-               }
-
-               /* Some OV518s have packet numbering by default, some don't */
-               if (mxps == 897)
-                       ov->packet_numbering = 1;
-               else
-                       ov->packet_numbering = 0;
-       } else {
-               /* OV518+ has packet numbering turned on by default */
-               ov->packet_numbering = 1;
-       }
-
-       ov518_set_packet_size(ov, 0);
-
-       ov->snap_enabled = snapshot;
-
-       /* Test for 76xx */
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               goto error;
-
-       /* The OV518 must be more aggressive about sensor detection since
-        * I2C write will never fail if the sensor is not present. We have
-        * to try to initialize the sensor to detect its presence */
-
-       if (init_ov_sensor(ov) < 0) {
-               /* Test for 6xx0 */
-               ov->primary_i2c_slave = OV6xx0_SID;
-               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-                       goto error;
-
-               if (init_ov_sensor(ov) < 0) {
-                       /* Test for 8xx0 */
-                       ov->primary_i2c_slave = OV8xx0_SID;
-                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-                               goto error;
-
-                       if (init_ov_sensor(ov) < 0) {
-                               err("Can't determine sensor slave IDs");
-                               goto error;
-                       } else {
-                               err("Detected unsupported OV8xx0 sensor");
-                               goto error;
-                       }
-               } else {
-                       if (ov6xx0_configure(ov) < 0) {
-                               err("Failed to configure OV6xx0");
-                               goto error;
-                       }
-               }
-       } else {
-               if (ov7xx0_configure(ov) < 0) {
-                       err("Failed to configure OV7xx0");
-                       goto error;
-               }
-       }
-
-       ov->maxwidth = 352;
-       ov->maxheight = 288;
-
-       // The OV518 cannot go as low as the sensor can
-       ov->minwidth = 160;
-       ov->minheight = 120;
-
-       return 0;
-
-error:
-       err("OV518 Config failed");
-
-       return -EBUSY;
-}
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-
-static inline struct usb_ov511 *cd_to_ov(struct device *cd)
-{
-       struct video_device *vdev = to_video_device(cd);
-       return video_get_drvdata(vdev);
-}
-
-static ssize_t show_custom_id(struct device *cd,
-                             struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%d\n", ov->customid);
-}
-static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-
-static ssize_t show_model(struct device *cd,
-                         struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", ov->desc);
-}
-static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_bridge(struct device *cd,
-                          struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
-}
-static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-
-static ssize_t show_sensor(struct device *cd,
-                          struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
-}
-static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-
-static ssize_t show_brightness(struct device *cd,
-                              struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_brightness(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct device *cd,
-                              struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_saturation(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_contrast(struct device *cd,
-                            struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_contrast(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_hue(struct device *cd,
-                       struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_hue(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_exposure(struct device *cd,
-                            struct device_attribute *attr, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned char exp = 0;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_exposure(ov, &exp);
-       return sprintf(buf, "%d\n", exp);
-}
-static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-
-static int ov_create_sysfs(struct video_device *vdev)
-{
-       int rc;
-
-       rc = device_create_file(&vdev->dev, &dev_attr_custom_id);
-       if (rc) goto err;
-       rc = device_create_file(&vdev->dev, &dev_attr_model);
-       if (rc) goto err_id;
-       rc = device_create_file(&vdev->dev, &dev_attr_bridge);
-       if (rc) goto err_model;
-       rc = device_create_file(&vdev->dev, &dev_attr_sensor);
-       if (rc) goto err_bridge;
-       rc = device_create_file(&vdev->dev, &dev_attr_brightness);
-       if (rc) goto err_sensor;
-       rc = device_create_file(&vdev->dev, &dev_attr_saturation);
-       if (rc) goto err_bright;
-       rc = device_create_file(&vdev->dev, &dev_attr_contrast);
-       if (rc) goto err_sat;
-       rc = device_create_file(&vdev->dev, &dev_attr_hue);
-       if (rc) goto err_contrast;
-       rc = device_create_file(&vdev->dev, &dev_attr_exposure);
-       if (rc) goto err_hue;
-
-       return 0;
-
-err_hue:
-       device_remove_file(&vdev->dev, &dev_attr_hue);
-err_contrast:
-       device_remove_file(&vdev->dev, &dev_attr_contrast);
-err_sat:
-       device_remove_file(&vdev->dev, &dev_attr_saturation);
-err_bright:
-       device_remove_file(&vdev->dev, &dev_attr_brightness);
-err_sensor:
-       device_remove_file(&vdev->dev, &dev_attr_sensor);
-err_bridge:
-       device_remove_file(&vdev->dev, &dev_attr_bridge);
-err_model:
-       device_remove_file(&vdev->dev, &dev_attr_model);
-err_id:
-       device_remove_file(&vdev->dev, &dev_attr_custom_id);
-err:
-       return rc;
-}
-
-/****************************************************************************
- *  USB routines
- ***************************************************************************/
-
-static int
-ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_interface_descriptor *idesc;
-       struct usb_ov511 *ov;
-       int i, rc, nr;
-
-       PDEBUG(1, "probing for device...");
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       idesc = &intf->cur_altsetting->desc;
-
-       if (idesc->bInterfaceClass != 0xFF)
-               return -ENODEV;
-       if (idesc->bInterfaceSubClass != 0x00)
-               return -ENODEV;
-
-       if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
-               err("couldn't kmalloc ov struct");
-               goto error_out;
-       }
-
-       ov->dev = dev;
-       ov->iface = idesc->bInterfaceNumber;
-       ov->led_policy = led;
-       ov->compress = compress;
-       ov->lightfreq = lightfreq;
-       ov->num_inputs = 1;        /* Video decoder init functs. change this */
-       ov->stop_during_set = !fastset;
-       ov->backlight = backlight;
-       ov->mirror = mirror;
-       ov->auto_brt = autobright;
-       ov->auto_gain = autogain;
-       ov->auto_exp = autoexp;
-
-       switch (le16_to_cpu(dev->descriptor.idProduct)) {
-       case PROD_OV511:
-               ov->bridge = BRG_OV511;
-               ov->bclass = BCL_OV511;
-               break;
-       case PROD_OV511PLUS:
-               ov->bridge = BRG_OV511PLUS;
-               ov->bclass = BCL_OV511;
-               break;
-       case PROD_OV518:
-               ov->bridge = BRG_OV518;
-               ov->bclass = BCL_OV518;
-               break;
-       case PROD_OV518PLUS:
-               ov->bridge = BRG_OV518PLUS;
-               ov->bclass = BCL_OV518;
-               break;
-       case PROD_ME2CAM:
-               if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
-                       goto error;
-               ov->bridge = BRG_OV511PLUS;
-               ov->bclass = BCL_OV511;
-               break;
-       default:
-               err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
-               goto error;
-       }
-
-       dev_info(&intf->dev, "USB %s video device found\n",
-                symbolic(brglist, ov->bridge));
-
-       init_waitqueue_head(&ov->wq);
-
-       mutex_init(&ov->lock);  /* to 1 == available */
-       mutex_init(&ov->buf_lock);
-       mutex_init(&ov->i2c_lock);
-       mutex_init(&ov->cbuf_lock);
-
-       ov->buf_state = BUF_NOT_ALLOCATED;
-
-       if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
-               err("usb_make_path error");
-               goto error;
-       }
-
-       /* Allocate control transfer buffer. */
-       /* Must be kmalloc()'ed, for DMA compatibility */
-       ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
-       if (!ov->cbuf)
-               goto error;
-
-       if (ov->bclass == BCL_OV518) {
-               if (ov518_configure(ov) < 0)
-                       goto error;
-       } else {
-               if (ov511_configure(ov) < 0)
-                       goto error;
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].framenum = i;
-               init_waitqueue_head(&ov->frame[i].wq);
-       }
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               ov->sbuf[i].ov = ov;
-               spin_lock_init(&ov->sbuf[i].lock);
-               ov->sbuf[i].n = i;
-       }
-
-       /* Unnecessary? (This is done on open(). Need to make sure variables
-        * are properly initialized without this before removing it, though). */
-       if (ov51x_set_default_params(ov) < 0)
-               goto error;
-
-#ifdef OV511_DEBUG
-       if (dump_bridge) {
-               if (ov->bclass == BCL_OV511)
-                       ov511_dump_regs(ov);
-               else
-                       ov518_dump_regs(ov);
-       }
-#endif
-
-       ov->vdev = video_device_alloc();
-       if (!ov->vdev)
-               goto error;
-
-       memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
-       ov->vdev->parent = &intf->dev;
-       video_set_drvdata(ov->vdev, ov);
-
-       mutex_lock(&ov->lock);
-
-       /* Check to see next free device and mark as used */
-       nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
-
-       /* Registers device */
-       if (unit_video[nr] != 0)
-               rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
-                                          unit_video[nr]);
-       else
-               rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
-
-       if (rc < 0) {
-               err("video_register_device failed");
-               mutex_unlock(&ov->lock);
-               goto error;
-       }
-
-       /* Mark device as used */
-       ov511_devused |= 1 << nr;
-       ov->nr = nr;
-
-       dev_info(&intf->dev, "Device at %s registered to %s\n",
-                ov->usb_path, video_device_node_name(ov->vdev));
-
-       usb_set_intfdata(intf, ov);
-       if (ov_create_sysfs(ov->vdev)) {
-               err("ov_create_sysfs failed");
-               ov511_devused &= ~(1 << nr);
-               mutex_unlock(&ov->lock);
-               goto error;
-       }
-
-       mutex_unlock(&ov->lock);
-
-       return 0;
-
-error:
-       if (ov->vdev) {
-               if (!video_is_registered(ov->vdev))
-                       video_device_release(ov->vdev);
-               else
-                       video_unregister_device(ov->vdev);
-               ov->vdev = NULL;
-       }
-
-       if (ov->cbuf) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-       }
-
-       kfree(ov);
-       ov = NULL;
-
-error_out:
-       err("Camera initialization failed");
-       return -EIO;
-}
-
-static void
-ov51x_disconnect(struct usb_interface *intf)
-{
-       struct usb_ov511 *ov = usb_get_intfdata(intf);
-       int n;
-
-       PDEBUG(3, "");
-
-       mutex_lock(&ov->lock);
-       usb_set_intfdata (intf, NULL);
-
-       /* Free device number */
-       ov511_devused &= ~(1 << ov->nr);
-
-       if (ov->vdev)
-               video_unregister_device(ov->vdev);
-
-       for (n = 0; n < OV511_NUMFRAMES; n++)
-               ov->frame[n].grabstate = FRAME_ERROR;
-
-       ov->curframe = -1;
-
-       /* This will cause the process to request another frame */
-       for (n = 0; n < OV511_NUMFRAMES; n++)
-               wake_up_interruptible(&ov->frame[n].wq);
-
-       wake_up_interruptible(&ov->wq);
-
-       ov->streaming = 0;
-       ov51x_unlink_isoc(ov);
-       mutex_unlock(&ov->lock);
-
-       ov->dev = NULL;
-
-       /* Free the memory */
-       if (!ov->user) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-
-               ov51x_dealloc(ov);
-               kfree(ov);
-               ov = NULL;
-       }
-
-       PDEBUG(3, "Disconnect complete");
-}
-
-static struct usb_driver ov511_driver = {
-       .name =         "ov511",
-       .id_table =     device_table,
-       .probe =        ov51x_probe,
-       .disconnect =   ov51x_disconnect
-};
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init
-usb_ov511_init(void)
-{
-       int retval;
-
-       retval = usb_register(&ov511_driver);
-       if (retval)
-               goto out;
-
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-              DRIVER_DESC "\n");
-
-out:
-       return retval;
-}
-
-static void __exit
-usb_ov511_exit(void)
-{
-       usb_deregister(&ov511_driver);
-       printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n");
-}
-
-module_init(usb_ov511_init);
-module_exit(usb_ov511_exit);
-
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
deleted file mode 100644 (file)
index c450c92..0000000
+++ /dev/null
@@ -1,573 +0,0 @@
-#ifndef __LINUX_OV511_H
-#define __LINUX_OV511_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#define OV511_DEBUG    /* Turn on debug messages */
-
-#ifdef OV511_DEBUG
-       #define PDEBUG(level, fmt, args...) \
-               if (debug >= (level))   \
-                       printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \
-               __func__, __LINE__ , ## args)
-#else
-       #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* 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); \
-}
-
-/* --------------------------------- */
-/* DEFINES FOR OV511 AND OTHER CHIPS */
-/* --------------------------------- */
-
-/* USB IDs */
-#define VEND_OMNIVISION        0x05A9
-#define PROD_OV511     0x0511
-#define PROD_OV511PLUS 0xA511
-#define PROD_OV518     0x0518
-#define PROD_OV518PLUS 0xA518
-
-#define VEND_MATTEL    0x0813
-#define PROD_ME2CAM    0x0002
-
-/* --------------------------------- */
-/*     OV51x REGISTER MNEMONICS      */
-/* --------------------------------- */
-
-/* Camera interface register numbers */
-#define R511_CAM_DELAY         0x10
-#define R511_CAM_EDGE          0x11
-#define R511_CAM_PXCNT         0x12
-#define R511_CAM_LNCNT         0x13
-#define R511_CAM_PXDIV         0x14
-#define R511_CAM_LNDIV         0x15
-#define R511_CAM_UV_EN         0x16
-#define R511_CAM_LINE_MODE     0x17
-#define R511_CAM_OPTS          0x18
-
-/* Snapshot mode camera interface register numbers */
-#define R511_SNAP_FRAME                0x19
-#define R511_SNAP_PXCNT                0x1A
-#define R511_SNAP_LNCNT                0x1B
-#define R511_SNAP_PXDIV                0x1C
-#define R511_SNAP_LNDIV                0x1D
-#define R511_SNAP_UV_EN                0x1E
-#define R511_SNAP_OPTS         0x1F
-
-/* DRAM register numbers */
-#define R511_DRAM_FLOW_CTL     0x20
-#define R511_DRAM_ARCP         0x21
-#define R511_DRAM_MRC          0x22
-#define R511_DRAM_RFC          0x23
-
-/* ISO FIFO register numbers */
-#define R51x_FIFO_PSIZE                0x30    /* 2 bytes wide w/ OV518(+) */
-#define R511_FIFO_OPTS         0x31
-
-/* Parallel IO register numbers */
-#define R511_PIO_OPTS          0x38
-#define R511_PIO_DATA          0x39
-#define R511_PIO_BIST          0x3E
-#define R518_GPIO_IN           0x55    /* OV518(+) only */
-#define R518_GPIO_OUT          0x56    /* OV518(+) only */
-#define R518_GPIO_CTL          0x57    /* OV518(+) only */
-#define R518_GPIO_PULSE_IN     0x58    /* OV518(+) only */
-#define R518_GPIO_PULSE_CLEAR  0x59    /* OV518(+) only */
-#define R518_GPIO_PULSE_POL    0x5a    /* OV518(+) only */
-#define R518_GPIO_PULSE_EN     0x5b    /* OV518(+) only */
-#define R518_GPIO_RESET                0x5c    /* OV518(+) only */
-
-/* I2C registers */
-#define R511_I2C_CTL           0x40
-#define R518_I2C_CTL           0x47    /* OV518(+) only */
-#define R51x_I2C_W_SID         0x41
-#define R51x_I2C_SADDR_3       0x42
-#define R51x_I2C_SADDR_2       0x43
-#define R51x_I2C_R_SID         0x44
-#define R51x_I2C_DATA          0x45
-#define R51x_I2C_CLOCK         0x46
-#define R51x_I2C_TIMEOUT       0x47
-
-/* I2C snapshot registers */
-#define R511_SI2C_SADDR_3      0x48
-#define R511_SI2C_DATA         0x49
-
-/* System control registers */
-#define R51x_SYS_RESET         0x50
-               /* Reset type definitions */
-#define        OV511_RESET_UDC         0x01
-#define        OV511_RESET_I2C         0x02
-#define        OV511_RESET_FIFO        0x04
-#define        OV511_RESET_OMNICE      0x08
-#define        OV511_RESET_DRAM        0x10
-#define        OV511_RESET_CAM_INT     0x20
-#define        OV511_RESET_OV511       0x40
-#define        OV511_RESET_NOREGS      0x3F /* All but OV511 & regs */
-#define        OV511_RESET_ALL         0x7F
-
-#define R511_SYS_CLOCK_DIV     0x51
-#define R51x_SYS_SNAP          0x52
-#define R51x_SYS_INIT          0x53
-#define R511_SYS_PWR_CLK       0x54 /* OV511+/OV518(+) only */
-#define R511_SYS_LED_CTL       0x55 /* OV511+ only */
-#define R511_SYS_USER          0x5E
-#define R511_SYS_CUST_ID       0x5F
-
-/* OmniCE (compression) registers */
-#define R511_COMP_PHY          0x70
-#define R511_COMP_PHUV         0x71
-#define R511_COMP_PVY          0x72
-#define R511_COMP_PVUV         0x73
-#define R511_COMP_QHY          0x74
-#define R511_COMP_QHUV         0x75
-#define R511_COMP_QVY          0x76
-#define R511_COMP_QVUV         0x77
-#define R511_COMP_EN           0x78
-#define R511_COMP_LUT_EN       0x79
-#define R511_COMP_LUT_BEGIN    0x80
-
-/* --------------------------------- */
-/*         ALTERNATE NUMBERS         */
-/* --------------------------------- */
-
-/* Alternate numbers for various max packet sizes (OV511 only) */
-#define OV511_ALT_SIZE_992     0
-#define OV511_ALT_SIZE_993     1
-#define OV511_ALT_SIZE_768     2
-#define OV511_ALT_SIZE_769     3
-#define OV511_ALT_SIZE_512     4
-#define OV511_ALT_SIZE_513     5
-#define OV511_ALT_SIZE_257     6
-#define OV511_ALT_SIZE_0       7
-
-/* Alternate numbers for various max packet sizes (OV511+ only) */
-#define OV511PLUS_ALT_SIZE_0   0
-#define OV511PLUS_ALT_SIZE_33  1
-#define OV511PLUS_ALT_SIZE_129 2
-#define OV511PLUS_ALT_SIZE_257 3
-#define OV511PLUS_ALT_SIZE_385 4
-#define OV511PLUS_ALT_SIZE_513 5
-#define OV511PLUS_ALT_SIZE_769 6
-#define OV511PLUS_ALT_SIZE_961 7
-
-/* Alternate numbers for various max packet sizes (OV518(+) only) */
-#define OV518_ALT_SIZE_0       0
-#define OV518_ALT_SIZE_128     1
-#define OV518_ALT_SIZE_256     2
-#define OV518_ALT_SIZE_384     3
-#define OV518_ALT_SIZE_512     4
-#define OV518_ALT_SIZE_640     5
-#define OV518_ALT_SIZE_768     6
-#define OV518_ALT_SIZE_896     7
-
-/* --------------------------------- */
-/*     OV7610 REGISTER MNEMONICS     */
-/* --------------------------------- */
-
-/* OV7610 registers */
-#define OV7610_REG_GAIN          0x00  /* gain setting (5:0) */
-#define OV7610_REG_BLUE          0x01  /* blue channel balance */
-#define OV7610_REG_RED           0x02  /* red channel balance */
-#define OV7610_REG_SAT           0x03  /* saturation */
-                                       /* 04 reserved */
-#define OV7610_REG_CNT           0x05  /* Y contrast */
-#define OV7610_REG_BRT           0x06  /* Y brightness */
-                                       /* 08-0b reserved */
-#define OV7610_REG_BLUE_BIAS     0x0C  /* blue channel bias (5:0) */
-#define OV7610_REG_RED_BIAS      0x0D  /* read channel bias (5:0) */
-#define OV7610_REG_GAMMA_COEFF   0x0E  /* gamma settings */
-#define OV7610_REG_WB_RANGE      0x0F  /* AEC/ALC/S-AWB settings */
-#define OV7610_REG_EXP           0x10  /* manual exposure setting */
-#define OV7610_REG_CLOCK         0x11  /* polarity/clock prescaler */
-#define OV7610_REG_COM_A         0x12  /* misc common regs */
-#define OV7610_REG_COM_B         0x13  /* misc common regs */
-#define OV7610_REG_COM_C         0x14  /* misc common regs */
-#define OV7610_REG_COM_D         0x15  /* misc common regs */
-#define OV7610_REG_FIELD_DIVIDE  0x16  /* field interval/mode settings */
-#define OV7610_REG_HWIN_START    0x17  /* horizontal window start */
-#define OV7610_REG_HWIN_END      0x18  /* horizontal window end */
-#define OV7610_REG_VWIN_START    0x19  /* vertical window start */
-#define OV7610_REG_VWIN_END      0x1A  /* vertical window end */
-#define OV7610_REG_PIXEL_SHIFT   0x1B  /* pixel shift */
-#define OV7610_REG_ID_HIGH       0x1C  /* manufacturer ID MSB */
-#define OV7610_REG_ID_LOW        0x1D  /* manufacturer ID LSB */
-                                       /* 0e-0f reserved */
-#define OV7610_REG_COM_E         0x20  /* misc common regs */
-#define OV7610_REG_YOFFSET       0x21  /* Y channel offset */
-#define OV7610_REG_UOFFSET       0x22  /* U channel offset */
-                                       /* 23 reserved */
-#define OV7610_REG_ECW           0x24  /* Exposure white level for AEC */
-#define OV7610_REG_ECB           0x25  /* Exposure black level for AEC */
-#define OV7610_REG_COM_F         0x26  /* misc settings */
-#define OV7610_REG_COM_G         0x27  /* misc settings */
-#define OV7610_REG_COM_H         0x28  /* misc settings */
-#define OV7610_REG_COM_I         0x29  /* misc settings */
-#define OV7610_REG_FRAMERATE_H   0x2A  /* frame rate MSB + misc */
-#define OV7610_REG_FRAMERATE_L   0x2B  /* frame rate LSB */
-#define OV7610_REG_ALC           0x2C  /* Auto Level Control settings */
-#define OV7610_REG_COM_J         0x2D  /* misc settings */
-#define OV7610_REG_VOFFSET       0x2E  /* V channel offset adjustment */
-#define OV7610_REG_ARRAY_BIAS   0x2F   /* Array bias -- don't change */
-                                       /* 30-32 reserved */
-#define OV7610_REG_YGAMMA        0x33  /* misc gamma settings (7:6) */
-#define OV7610_REG_BIAS_ADJUST   0x34  /* misc bias settings */
-#define OV7610_REG_COM_L         0x35  /* misc settings */
-                                       /* 36-37 reserved */
-#define OV7610_REG_COM_K         0x38  /* misc registers */
-
-/* --------------------------------- */
-/*           I2C ADDRESSES           */
-/* --------------------------------- */
-
-#define OV7xx0_SID   0x42
-#define OV6xx0_SID   0xC0
-#define OV8xx0_SID   0xA0
-#define KS0127_SID   0xD8
-#define SAA7111A_SID 0x48
-
-/* --------------------------------- */
-/*       MISCELLANEOUS DEFINES       */
-/* --------------------------------- */
-
-#define I2C_CLOCK_PRESCALER    0x03
-
-#define FRAMES_PER_DESC                10      /* FIXME - What should this be? */
-#define MAX_FRAME_SIZE_PER_DESC        993     /* For statically allocated stuff */
-#define PIXELS_PER_SEG         256     /* Pixels per segment */
-
-#define OV511_ENDPOINT_ADDRESS 1       /* Isoc endpoint number */
-
-#define OV511_NUMFRAMES        2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-       #error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF          2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE                4
-
-/* Size of usb_make_path() buffer */
-#define OV511_USB_PATH_LEN     64
-
-/* Bridge types */
-enum {
-       BRG_UNKNOWN,
-       BRG_OV511,
-       BRG_OV511PLUS,
-       BRG_OV518,
-       BRG_OV518PLUS,
-};
-
-/* Bridge classes */
-enum {
-       BCL_UNKNOWN,
-       BCL_OV511,
-       BCL_OV518,
-};
-
-/* Sensor types */
-enum {
-       SEN_UNKNOWN,
-       SEN_OV76BE,
-       SEN_OV7610,
-       SEN_OV7620,
-       SEN_OV7620AE,
-       SEN_OV6620,
-       SEN_OV6630,
-       SEN_OV6630AE,
-       SEN_OV6630AF,
-       SEN_OV8600,
-       SEN_KS0127,
-       SEN_KS0127B,
-       SEN_SAA7111A,
-};
-
-enum {
-       STATE_SCANNING,         /* Scanning for start */
-       STATE_HEADER,           /* Parsing header */
-       STATE_LINES,            /* Parsing lines */
-};
-
-/* Buffer states */
-enum {
-       BUF_NOT_ALLOCATED,
-       BUF_ALLOCATED,
-};
-
-/* --------- Definition of ioctl interface --------- */
-
-#define OV511_INTERFACE_VER 101
-
-/* LED options */
-enum {
-       LED_OFF,
-       LED_ON,
-       LED_AUTO,
-};
-
-/* Raw frame formats */
-enum {
-       RAWFMT_INVALID,
-       RAWFMT_YUV400,
-       RAWFMT_YUV420,
-       RAWFMT_YUV422,
-       RAWFMT_GBR422,
-};
-
-struct ov511_i2c_struct {
-       unsigned char slave; /* Write slave ID (read ID - 1) */
-       unsigned char reg;   /* Index of register */
-       unsigned char value; /* User sets this w/ write, driver does w/ read */
-       unsigned char mask;  /* Bits to be changed. Not used with read ops */
-};
-
-/* ioctls */
-#define OV511IOC_WI2C     _IOW('v', BASE_VIDIOCPRIVATE + 5, \
-                              struct ov511_i2c_struct)
-#define OV511IOC_RI2C    _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
-                              struct ov511_i2c_struct)
-/* ------------- End IOCTL interface -------------- */
-
-struct usb_ov511;              /* Forward declaration */
-
-struct ov511_sbuf {
-       struct usb_ov511 *ov;
-       unsigned char *data;
-       struct urb *urb;
-       spinlock_t lock;
-       int n;
-};
-
-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 */
-};
-
-struct ov511_regvals {
-       enum {
-               OV511_DONE_BUS,
-               OV511_REG_BUS,
-               OV511_I2C_BUS,
-       } bus;
-       unsigned char reg;
-       unsigned char val;
-};
-
-struct ov511_frame {
-       int framenum;           /* Index of this frame */
-       unsigned char *data;    /* Frame buffer */
-       unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
-       unsigned char *rawdata; /* Raw camera data buffer */
-       unsigned char *compbuf; /* Temp buffer for decompressor */
-
-       int depth;              /* Bytes per pixel */
-       int width;              /* Width application is expecting */
-       int height;             /* Height application is expecting */
-
-       int rawwidth;           /* Actual width of frame sent from camera */
-       int rawheight;          /* Actual height of frame sent from camera */
-
-       int sub_flag;           /* Sub-capture mode for this frame? */
-       unsigned int format;    /* Format for this frame */
-       int compressed;         /* Is frame compressed? */
-
-       volatile int grabstate; /* State of grabbing */
-       int scanstate;          /* State of scanning */
-
-       int bytes_recvd;        /* Number of image bytes received from camera */
-
-       long bytes_read;        /* Amount that has been read() */
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int snapshot;           /* True if frame was a snapshot */
-};
-
-#define DECOMP_INTERFACE_VER 4
-
-/* Compression module operations */
-struct ov51x_decomp_ops {
-       int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       struct module *owner;
-};
-
-struct usb_ov511 {
-       struct video_device *vdev;
-       struct usb_device *dev;
-
-       int customid;
-       char *desc;
-       unsigned char iface;
-       char usb_path[OV511_USB_PATH_LEN];
-
-       /* Determined by sensor type */
-       int maxwidth;
-       int maxheight;
-       int minwidth;
-       int minheight;
-
-       int brightness;
-       int colour;
-       int contrast;
-       int hue;
-       int whiteness;
-       int exposure;
-       int auto_brt;           /* Auto brightness enabled flag */
-       int auto_gain;          /* Auto gain control enabled flag */
-       int auto_exp;           /* Auto exposure enabled flag */
-       int backlight;          /* Backlight exposure algorithm flag */
-       int mirror;             /* Image is reversed horizontally */
-
-       int led_policy;         /* LED: off|on|auto; OV511+ only */
-
-       struct mutex lock;      /* Serializes user-accessible operations */
-       int user;               /* user count for exclusive use */
-
-       int streaming;          /* Are we streaming Isochronous? */
-       int grabbing;           /* Are we grabbing? */
-
-       int compress;           /* Should the next frame be compressed? */
-       int compress_inited;    /* Are compression params uploaded? */
-
-       int lightfreq;          /* Power (lighting) frequency */
-       int bandfilt;           /* Banding filter enabled flag */
-
-       unsigned char *fbuf;    /* Videodev buffer area */
-       unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
-       unsigned char *rawfbuf; /* Raw camera data buffer area */
-
-       int sub_flag;           /* Pix Array subcapture on flag */
-       int subx;               /* Pix Array subcapture x offset */
-       int suby;               /* Pix Array subcapture y offset */
-       int subw;               /* Pix Array subcapture width */
-       int subh;               /* Pix Array subcapture height */
-
-       int curframe;           /* Current receiving sbuf */
-       struct ov511_frame frame[OV511_NUMFRAMES];
-
-       struct ov511_sbuf sbuf[OV511_NUMSBUF];
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int snap_enabled;       /* Snapshot mode enabled */
-
-       int bridge;             /* Type of bridge (BRG_*) */
-       int bclass;             /* Class of bridge (BCL_*) */
-       int sensor;             /* Type of image sensor chip (SEN_*) */
-
-       int packet_size;        /* Frame size per isoc desc */
-       int packet_numbering;   /* Is ISO frame numbering enabled? */
-
-       /* Framebuffer/sbuf management */
-       int buf_state;
-       struct mutex buf_lock;
-
-       struct ov51x_decomp_ops *decomp_ops;
-
-       /* Stop streaming while changing picture settings */
-       int stop_during_set;
-
-       int stopped;            /* Streaming is temporarily paused */
-
-       /* Video decoder stuff */
-       int input;              /* Composite, S-VIDEO, etc... */
-       int num_inputs;         /* Number of inputs */
-       int norm;               /* NTSC / PAL / SECAM */
-       int has_decoder;        /* Device has a video decoder */
-       int pal;                /* Device is designed for PAL resolution */
-
-       /* ov511 device number ID */
-       int nr;                 /* Stores a device number */
-
-       /* I2C interface */
-       struct mutex i2c_lock;    /* Protect I2C controller regs */
-       unsigned char primary_i2c_slave;  /* I2C write id of sensor */
-
-       /* Control transaction stuff */
-       unsigned char *cbuf;            /* Buffer for payload */
-       struct mutex cbuf_lock;
-};
-
-/* Used to represent a list of values and their respective symbolic names */
-struct symbolic_list {
-       int num;
-       char *name;
-};
-
-#define NOT_DEFINED_STR "Unknown"
-
-/* Returns the name of the matching element in the symbolic_list array. The
- * end of the list must be marked with an element that has a NULL name.
- */
-static inline char *
-symbolic(struct symbolic_list list[], int num)
-{
-       int i;
-
-       for (i = 0; list[i].name != NULL; i++)
-                       if (list[i].num == num)
-                               return (list[i].name);
-
-       return (NOT_DEFINED_STR);
-}
-
-/* Compression stuff */
-
-#define OV511_QUANTABLESIZE    64
-#define OV518_QUANTABLESIZE    32
-
-#define OV511_YQUANTABLE { \
-       0, 1, 1, 2, 2, 3, 3, 4, \
-       1, 1, 1, 2, 2, 3, 4, 4, \
-       1, 1, 2, 2, 3, 4, 4, 4, \
-       2, 2, 2, 3, 4, 4, 4, 4, \
-       2, 2, 3, 4, 4, 5, 5, 5, \
-       3, 3, 4, 4, 5, 5, 5, 5, \
-       3, 4, 4, 4, 5, 5, 5, 5, \
-       4, 4, 4, 4, 5, 5, 5, 5  \
-}
-
-#define OV511_UVQUANTABLE { \
-       0, 2, 2, 3, 4, 4, 4, 4, \
-       2, 2, 2, 4, 4, 4, 4, 4, \
-       2, 2, 3, 4, 4, 4, 4, 4, \
-       3, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4  \
-}
-
-#define OV518_YQUANTABLE { \
-       5, 4, 5, 6, 6, 7, 7, 7, \
-       5, 5, 5, 5, 6, 7, 7, 7, \
-       6, 6, 6, 6, 7, 7, 7, 8, \
-       7, 7, 6, 7, 7, 7, 8, 8  \
-}
-
-#define OV518_UVQUANTABLE { \
-       6, 6, 6, 7, 7, 7, 7, 7, \
-       6, 6, 6, 7, 7, 7, 7, 7, \
-       6, 6, 6, 7, 7, 7, 7, 8, \
-       7, 7, 7, 7, 7, 7, 8, 8  \
-}
-
-#endif
index 34034a710214e39b30f6f194f5cde31383aa9636..25eb5d637eeaccb9688f852abcf7c6921ed45709 100644 (file)
@@ -440,21 +440,21 @@ static const struct regval_list ov772x_vga_regs[] = {
  */
 static const struct ov772x_color_format ov772x_cfmts[] = {
        {
-               .code           = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+               .code           = V4L2_MBUS_FMT_YUYV8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .dsp3           = 0x0,
                .com3           = SWAP_YUV,
                .com7           = OFMT_YUV,
        },
        {
-               .code           = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+               .code           = V4L2_MBUS_FMT_YVYU8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .dsp3           = UV_ON,
                .com3           = SWAP_YUV,
                .com7           = OFMT_YUV,
        },
        {
-               .code           = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+               .code           = V4L2_MBUS_FMT_UYVY8_2X8,
                .colorspace     = V4L2_COLORSPACE_JPEG,
                .dsp3           = 0x0,
                .com3           = 0x0,
@@ -960,7 +960,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
        if (!priv->win || !priv->cfmt) {
                u32 width = VGA_WIDTH, height = VGA_HEIGHT;
                int ret = ov772x_set_params(client, &width, &height,
-                                           V4L2_MBUS_FMT_YUYV8_2X8_LE);
+                                           V4L2_MBUS_FMT_YUYV8_2X8);
                if (ret < 0)
                        return ret;
        }
index 7ce9e05b47815c764baa56d087dab3d47b4b228d..40cdfab74ccc8cfbf25ecc5a5fff3b5853541256 100644 (file)
@@ -155,7 +155,7 @@ static const struct ov9640_reg ov9640_regs_rgb[] = {
 };
 
 static enum v4l2_mbus_pixelcode ov9640_codes[] = {
-       V4L2_MBUS_FMT_YUYV8_2X8_BE,
+       V4L2_MBUS_FMT_UYVY8_2X8,
        V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
        V4L2_MBUS_FMT_RGB565_2X8_LE,
 };
@@ -430,7 +430,7 @@ static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
 {
        switch (code) {
        default:
-       case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
                alt->com12      = OV9640_COM12_YUV_AVG;
                alt->com13      = OV9640_COM13_Y_DELAY_EN |
                                        OV9640_COM13_YUV_DLY(0x01);
@@ -493,7 +493,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width,
        }
 
        /* select color matrix configuration for given color encoding */
-       if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) {
+       if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
                matrix_regs     = ov9640_regs_yuv;
                matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
        } else {
@@ -579,8 +579,8 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
                cspace = V4L2_COLORSPACE_SRGB;
                break;
        default:
-               code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
-       case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+               code = V4L2_MBUS_FMT_UYVY8_2X8;
+       case V4L2_MBUS_FMT_UYVY8_2X8:
                cspace = V4L2_COLORSPACE_JPEG;
        }
 
@@ -606,8 +606,8 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
                mf->colorspace = V4L2_COLORSPACE_SRGB;
                break;
        default:
-               mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
-       case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+               mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+       case V4L2_MBUS_FMT_UYVY8_2X8:
                mf->colorspace = V4L2_COLORSPACE_JPEG;
        }
 
diff --git a/drivers/media/video/ovcamchip/Makefile b/drivers/media/video/ovcamchip/Makefile
deleted file mode 100644 (file)
index cba4cdf..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-ovcamchip-objs     := ovcamchip_core.o ov6x20.o ov6x30.o ov7x10.o ov7x20.o \
-                     ov76be.o
-
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip.o
diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c
deleted file mode 100644 (file)
index c04130d..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/* OmniVision OV6620/OV6120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN               0x00    /* gain [5:0] */
-#define REG_BLUE               0x01    /* blue gain */
-#define REG_RED                        0x02    /* red gain */
-#define REG_SAT                        0x03    /* saturation */
-#define REG_CNT                        0x05    /* Y contrast */
-#define REG_BRT                        0x06    /* Y brightness */
-#define REG_WB_BLUE            0x0C    /* WB blue ratio [5:0] */
-#define REG_WB_RED             0x0D    /* WB red ratio [5:0] */
-#define REG_EXP                        0x10    /* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x20 {
-       int auto_brt;
-       int auto_exp;
-       int backlight;
-       int bandfilt;
-       int mirror;
-};
-
-/* Initial values for use with OV511/OV511+ cameras */
-static struct ovcamchip_regvals regvals_init_6x20_511[] = {
-       { 0x12, 0x80 }, /* reset */
-       { 0x11, 0x01 },
-       { 0x03, 0x60 },
-       { 0x05, 0x7f }, /* For when autoadjust is off */
-       { 0x07, 0xa8 },
-       { 0x0c, 0x24 },
-       { 0x0d, 0x24 },
-       { 0x0f, 0x15 }, /* COMS */
-       { 0x10, 0x75 }, /* AEC Exposure time */
-       { 0x12, 0x24 }, /* Enable AGC and AWB */
-       { 0x14, 0x04 },
-       { 0x16, 0x03 },
-       { 0x26, 0xb2 }, /* BLC enable */
-       /* 0x28: 0x05 Selects RGB format if RGB on */
-       { 0x28, 0x05 },
-       { 0x2a, 0x04 }, /* Disable framerate adjust */
-       { 0x2d, 0x99 },
-       { 0x33, 0xa0 }, /* Color Processing Parameter */
-       { 0x34, 0xd2 }, /* Max A/D range */
-       { 0x38, 0x8b },
-       { 0x39, 0x40 },
-
-       { 0x3c, 0x39 }, /* Enable AEC mode changing */
-       { 0x3c, 0x3c }, /* Change AEC mode */
-       { 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-       { 0x3d, 0x80 },
-       /* These next two registers (0x4a, 0x4b) are undocumented. They
-        * control the color balance */
-       { 0x4a, 0x80 },
-       { 0x4b, 0x80 },
-       { 0x4d, 0xd2 }, /* This reduces noise a bit */
-       { 0x4e, 0xc1 },
-       { 0x4f, 0x04 },
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Initial values for use with OV518 cameras */
-static struct ovcamchip_regvals regvals_init_6x20_518[] = {
-       { 0x12, 0x80 }, /* Do a reset */
-       { 0x03, 0xc0 }, /* Saturation */
-       { 0x05, 0x8a }, /* Contrast */
-       { 0x0c, 0x24 }, /* AWB blue */
-       { 0x0d, 0x24 }, /* AWB red */
-       { 0x0e, 0x8d }, /* Additional 2x gain */
-       { 0x0f, 0x25 }, /* Black expanding level = 1.3V */
-       { 0x11, 0x01 }, /* Clock div. */
-       { 0x12, 0x24 }, /* Enable AGC and AWB */
-       { 0x13, 0x01 }, /* (default) */
-       { 0x14, 0x80 }, /* Set reserved bit 7 */
-       { 0x15, 0x01 }, /* (default) */
-       { 0x16, 0x03 }, /* (default) */
-       { 0x17, 0x38 }, /* (default) */
-       { 0x18, 0xea }, /* (default) */
-       { 0x19, 0x04 },
-       { 0x1a, 0x93 },
-       { 0x1b, 0x00 }, /* (default) */
-       { 0x1e, 0xc4 }, /* (default) */
-       { 0x1f, 0x04 }, /* (default) */
-       { 0x20, 0x20 }, /* Enable 1st stage aperture correction */
-       { 0x21, 0x10 }, /* Y offset */
-       { 0x22, 0x88 }, /* U offset */
-       { 0x23, 0xc0 }, /* Set XTAL power level */
-       { 0x24, 0x53 }, /* AEC bright ratio */
-       { 0x25, 0x7a }, /* AEC black ratio */
-       { 0x26, 0xb2 }, /* BLC enable */
-       { 0x27, 0xa2 }, /* Full output range */
-       { 0x28, 0x01 }, /* (default) */
-       { 0x29, 0x00 }, /* (default) */
-       { 0x2a, 0x84 }, /* (default) */
-       { 0x2b, 0xa8 }, /* Set custom frame rate */
-       { 0x2c, 0xa0 }, /* (reserved) */
-       { 0x2d, 0x95 }, /* Enable banding filter */
-       { 0x2e, 0x88 }, /* V offset */
-       { 0x33, 0x22 }, /* Luminance gamma on */
-       { 0x34, 0xc7 }, /* A/D bias */
-       { 0x36, 0x12 }, /* (reserved) */
-       { 0x37, 0x63 }, /* (reserved) */
-       { 0x38, 0x8b }, /* Quick AEC/AEB */
-       { 0x39, 0x00 }, /* (default) */
-       { 0x3a, 0x0f }, /* (default) */
-       { 0x3b, 0x3c }, /* (default) */
-       { 0x3c, 0x5c }, /* AEC controls */
-       { 0x3d, 0x80 }, /* Drop 1 (bad) frame when AEC change */
-       { 0x3e, 0x80 }, /* (default) */
-       { 0x3f, 0x02 }, /* (default) */
-       { 0x40, 0x10 }, /* (reserved) */
-       { 0x41, 0x10 }, /* (reserved) */
-       { 0x42, 0x00 }, /* (reserved) */
-       { 0x43, 0x7f }, /* (reserved) */
-       { 0x44, 0x80 }, /* (reserved) */
-       { 0x45, 0x1c }, /* (reserved) */
-       { 0x46, 0x1c }, /* (reserved) */
-       { 0x47, 0x80 }, /* (reserved) */
-       { 0x48, 0x5f }, /* (reserved) */
-       { 0x49, 0x00 }, /* (reserved) */
-       { 0x4a, 0x00 }, /* Color balance (undocumented) */
-       { 0x4b, 0x80 }, /* Color balance (undocumented) */
-       { 0x4c, 0x58 }, /* (reserved) */
-       { 0x4d, 0xd2 }, /* U *= .938, V *= .838 */
-       { 0x4e, 0xa0 }, /* (default) */
-       { 0x4f, 0x04 }, /* UV 3-point average */
-       { 0x50, 0xff }, /* (reserved) */
-       { 0x51, 0x58 }, /* (reserved) */
-       { 0x52, 0xc0 }, /* (reserved) */
-       { 0x53, 0x42 }, /* (reserved) */
-       { 0x27, 0xa6 }, /* Enable manual offset adj. (reg 21 & 22) */
-       { 0x12, 0x20 },
-       { 0x12, 0x24 },
-
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV6x20 camera chip and relevant variables. */
-static int ov6x20_init(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov6x20 *s;
-       int rc;
-
-       DDEBUG(4, &c->dev, "entered");
-
-       switch (c->adapter->id) {
-       case I2C_HW_SMBUS_OV511:
-               rc = ov_write_regvals(c, regvals_init_6x20_511);
-               break;
-       case I2C_HW_SMBUS_OV518:
-               rc = ov_write_regvals(c, regvals_init_6x20_518);
-               break;
-       default:
-               dev_err(&c->dev, "ov6x20: Unsupported adapter\n");
-               rc = -ENODEV;
-       }
-
-       if (rc < 0)
-               return rc;
-
-       ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
-
-       s->auto_brt = 1;
-       s->auto_exp = 1;
-
-       return rc;
-}
-
-static int ov6x20_free(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-
-       kfree(ov->spriv);
-       return 0;
-}
-
-static int ov6x20_set_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov6x20 *s = ov->spriv;
-       int rc;
-       int v = ctl->value;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_write(c, REG_CNT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_write(c, REG_BRT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_write(c, REG_SAT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_HUE:
-               rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, REG_BLUE, v >> 8);
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_write(c, REG_EXP, v);
-               break;
-       case OVCAMCHIP_CID_FREQ:
-       {
-               int sixty = (v == 60);
-
-               rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
-               break;
-       }
-       case OVCAMCHIP_CID_BANDFILT:
-               rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-               s->bandfilt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-               s->auto_brt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
-               s->auto_exp = v;
-               break;
-       case OVCAMCHIP_CID_BACKLIGHT:
-       {
-               rc = ov_write_mask(c, 0x4e, v?0xe0:0xc0, 0xe0);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x0e, v?0x80:0x00, 0x80);
-               s->backlight = v;
-               break;
-       }
-       case OVCAMCHIP_CID_MIRROR:
-               rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-               s->mirror = v;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-out:
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-       return rc;
-}
-
-static int ov6x20_get_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov6x20 *s = ov->spriv;
-       int rc = 0;
-       unsigned char val = 0;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_read(c, REG_CNT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_read(c, REG_BRT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_read(c, REG_SAT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_HUE:
-               rc = ov_read(c, REG_BLUE, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_read(c, REG_EXP, &val);
-               ctl->value = val;
-               break;
-       case OVCAMCHIP_CID_BANDFILT:
-               ctl->value = s->bandfilt;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               ctl->value = s->auto_brt;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               ctl->value = s->auto_exp;
-               break;
-       case OVCAMCHIP_CID_BACKLIGHT:
-               ctl->value = s->backlight;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               ctl->value = s->mirror;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-       return rc;
-}
-
-static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       /******** QCIF-specific regs ********/
-
-       ov_write(c, 0x14, win->quarter?0x24:0x04);
-
-       /******** Palette-specific regs ********/
-
-       /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
-       if (c->adapter->id == I2C_HW_SMBUS_OV518) {
-               if (win->format == VIDEO_PALETTE_GREY)
-                       ov_write_mask(c, 0x13, 0x00, 0x20);
-               else
-                       ov_write_mask(c, 0x13, 0x20, 0x20);
-       } else {
-               if (win->format == VIDEO_PALETTE_GREY)
-                       ov_write_mask(c, 0x13, 0x20, 0x20);
-               else
-                       ov_write_mask(c, 0x13, 0x00, 0x20);
-       }
-
-       /******** Clock programming ********/
-
-       /* The OV6620 needs special handling. This prevents the
-        * severe banding that normally occurs */
-
-       /* Clock down */
-       ov_write(c, 0x2a, 0x04);
-
-       ov_write(c, 0x11, win->clockdiv);
-
-       ov_write(c, 0x2a, 0x84);
-       /* This next setting is critical. It seems to improve
-        * the gain or the contrast. The "reserved" bits seem
-        * to have some effect in this case. */
-       ov_write(c, 0x2d, 0x85); /* FIXME: This messes up banding filter */
-
-       return 0;
-}
-
-static int ov6x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int ret, hwscale, vwscale;
-
-       ret = ov6x20_mode_init(c, win);
-       if (ret < 0)
-               return ret;
-
-       if (win->quarter) {
-               hwscale = 0;
-               vwscale = 0;
-       } else {
-               hwscale = 1;
-               vwscale = 1;    /* The datasheet says 0; it's wrong */
-       }
-
-       ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-       ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-       ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-       ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-       return 0;
-}
-
-static int ov6x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case OVCAMCHIP_CMD_S_CTRL:
-               return ov6x20_set_control(c, arg);
-       case OVCAMCHIP_CMD_G_CTRL:
-               return ov6x20_get_control(c, arg);
-       case OVCAMCHIP_CMD_S_MODE:
-               return ov6x20_set_window(c, arg);
-       default:
-               DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-               return -ENOIOCTLCMD;
-       }
-}
-
-struct ovcamchip_ops ov6x20_ops = {
-       .init    =      ov6x20_init,
-       .free    =      ov6x20_free,
-       .command =      ov6x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c
deleted file mode 100644 (file)
index 73b94f5..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/* OmniVision OV6630/OV6130 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN               0x00    /* gain [5:0] */
-#define REG_BLUE               0x01    /* blue gain */
-#define REG_RED                        0x02    /* red gain */
-#define REG_SAT                        0x03    /* saturation [7:3] */
-#define REG_CNT                        0x05    /* Y contrast [3:0] */
-#define REG_BRT                        0x06    /* Y brightness */
-#define REG_SHARP              0x07    /* sharpness */
-#define REG_WB_BLUE            0x0C    /* WB blue ratio [5:0] */
-#define REG_WB_RED             0x0D    /* WB red ratio [5:0] */
-#define REG_EXP                        0x10    /* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x30 {
-       int auto_brt;
-       int auto_exp;
-       int backlight;
-       int bandfilt;
-       int mirror;
-};
-
-static struct ovcamchip_regvals regvals_init_6x30[] = {
-       { 0x12, 0x80 }, /* reset */
-       { 0x00, 0x1f }, /* Gain */
-       { 0x01, 0x99 }, /* Blue gain */
-       { 0x02, 0x7c }, /* Red gain */
-       { 0x03, 0xc0 }, /* Saturation */
-       { 0x05, 0x0a }, /* Contrast */
-       { 0x06, 0x95 }, /* Brightness */
-       { 0x07, 0x2d }, /* Sharpness */
-       { 0x0c, 0x20 },
-       { 0x0d, 0x20 },
-       { 0x0e, 0x20 },
-       { 0x0f, 0x05 },
-       { 0x10, 0x9a }, /* "exposure check" */
-       { 0x11, 0x00 }, /* Pixel clock = fastest */
-       { 0x12, 0x24 }, /* Enable AGC and AWB */
-       { 0x13, 0x21 },
-       { 0x14, 0x80 },
-       { 0x15, 0x01 },
-       { 0x16, 0x03 },
-       { 0x17, 0x38 },
-       { 0x18, 0xea },
-       { 0x19, 0x04 },
-       { 0x1a, 0x93 },
-       { 0x1b, 0x00 },
-       { 0x1e, 0xc4 },
-       { 0x1f, 0x04 },
-       { 0x20, 0x20 },
-       { 0x21, 0x10 },
-       { 0x22, 0x88 },
-       { 0x23, 0xc0 }, /* Crystal circuit power level */
-       { 0x25, 0x9a }, /* Increase AEC black pixel ratio */
-       { 0x26, 0xb2 }, /* BLC enable */
-       { 0x27, 0xa2 },
-       { 0x28, 0x00 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x84 }, /* (keep) */
-       { 0x2b, 0xa8 }, /* (keep) */
-       { 0x2c, 0xa0 },
-       { 0x2d, 0x95 }, /* Enable auto-brightness */
-       { 0x2e, 0x88 },
-       { 0x33, 0x26 },
-       { 0x34, 0x03 },
-       { 0x36, 0x8f },
-       { 0x37, 0x80 },
-       { 0x38, 0x83 },
-       { 0x39, 0x80 },
-       { 0x3a, 0x0f },
-       { 0x3b, 0x3c },
-       { 0x3c, 0x1a },
-       { 0x3d, 0x80 },
-       { 0x3e, 0x80 },
-       { 0x3f, 0x0e },
-       { 0x40, 0x00 }, /* White bal */
-       { 0x41, 0x00 }, /* White bal */
-       { 0x42, 0x80 },
-       { 0x43, 0x3f }, /* White bal */
-       { 0x44, 0x80 },
-       { 0x45, 0x20 },
-       { 0x46, 0x20 },
-       { 0x47, 0x80 },
-       { 0x48, 0x7f },
-       { 0x49, 0x00 },
-       { 0x4a, 0x00 },
-       { 0x4b, 0x80 },
-       { 0x4c, 0xd0 },
-       { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-       { 0x4e, 0x40 },
-       { 0x4f, 0x07 }, /* UV average mode, color killer: strongest */
-       { 0x50, 0xff },
-       { 0x54, 0x23 }, /* Max AGC gain: 18dB */
-       { 0x55, 0xff },
-       { 0x56, 0x12 },
-       { 0x57, 0x81 }, /* (default) */
-       { 0x58, 0x75 },
-       { 0x59, 0x01 }, /* AGC dark current compensation: +1 */
-       { 0x5a, 0x2c },
-       { 0x5b, 0x0f }, /* AWB chrominance levels */
-       { 0x5c, 0x10 },
-       { 0x3d, 0x80 },
-       { 0x27, 0xa6 },
-       /* Toggle AWB off and on */
-       { 0x12, 0x20 },
-       { 0x12, 0x24 },
-
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV6x30 camera chip and relevant variables. */
-static int ov6x30_init(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov6x30 *s;
-       int rc;
-
-       DDEBUG(4, &c->dev, "entered");
-
-       rc = ov_write_regvals(c, regvals_init_6x30);
-       if (rc < 0)
-               return rc;
-
-       ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
-
-       s->auto_brt = 1;
-       s->auto_exp = 1;
-
-       return rc;
-}
-
-static int ov6x30_free(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-
-       kfree(ov->spriv);
-       return 0;
-}
-
-static int ov6x30_set_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov6x30 *s = ov->spriv;
-       int rc;
-       int v = ctl->value;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_write_mask(c, REG_CNT, v >> 12, 0x0f);
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_write(c, REG_BRT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_write(c, REG_SAT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_HUE:
-               rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, REG_BLUE, v >> 8);
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_write(c, REG_EXP, v);
-               break;
-       case OVCAMCHIP_CID_FREQ:
-       {
-               int sixty = (v == 60);
-
-               rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
-               break;
-       }
-       case OVCAMCHIP_CID_BANDFILT:
-               rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-               s->bandfilt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-               s->auto_brt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               rc = ov_write_mask(c, 0x28, v?0x00:0x10, 0x10);
-               s->auto_exp = v;
-               break;
-       case OVCAMCHIP_CID_BACKLIGHT:
-       {
-               rc = ov_write_mask(c, 0x4e, v?0x80:0x60, 0xe0);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
-               s->backlight = v;
-               break;
-       }
-       case OVCAMCHIP_CID_MIRROR:
-               rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-               s->mirror = v;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-out:
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-       return rc;
-}
-
-static int ov6x30_get_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov6x30 *s = ov->spriv;
-       int rc = 0;
-       unsigned char val = 0;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_read(c, REG_CNT, &val);
-               ctl->value = (val & 0x0f) << 12;
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_read(c, REG_BRT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_read(c, REG_SAT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_HUE:
-               rc = ov_read(c, REG_BLUE, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_read(c, REG_EXP, &val);
-               ctl->value = val;
-               break;
-       case OVCAMCHIP_CID_BANDFILT:
-               ctl->value = s->bandfilt;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               ctl->value = s->auto_brt;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               ctl->value = s->auto_exp;
-               break;
-       case OVCAMCHIP_CID_BACKLIGHT:
-               ctl->value = s->backlight;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               ctl->value = s->mirror;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-       return rc;
-}
-
-static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       /******** QCIF-specific regs ********/
-
-       ov_write_mask(c, 0x14, win->quarter?0x20:0x00, 0x20);
-
-       /******** Palette-specific regs ********/
-
-       if (win->format == VIDEO_PALETTE_GREY) {
-               if (c->adapter->id == I2C_HW_SMBUS_OV518) {
-                       /* Do nothing - we're already in 8-bit mode */
-               } else {
-                       ov_write_mask(c, 0x13, 0x20, 0x20);
-               }
-       } else {
-               /* The OV518 needs special treatment. Although both the OV518
-                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-                * bus is actually used. The UV bus is tied to ground.
-                * Therefore, the OV6630 needs to be in 8-bit multiplexed
-                * output mode */
-
-               if (c->adapter->id == I2C_HW_SMBUS_OV518) {
-                       /* Do nothing - we want to stay in 8-bit mode */
-                       /* Warning: Messing with reg 0x13 breaks OV518 color */
-               } else {
-                       ov_write_mask(c, 0x13, 0x00, 0x20);
-               }
-       }
-
-       /******** Clock programming ********/
-
-       ov_write(c, 0x11, win->clockdiv);
-
-       return 0;
-}
-
-static int ov6x30_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int ret, hwscale, vwscale;
-
-       ret = ov6x30_mode_init(c, win);
-       if (ret < 0)
-               return ret;
-
-       if (win->quarter) {
-               hwscale = 0;
-               vwscale = 0;
-       } else {
-               hwscale = 1;
-               vwscale = 1;    /* The datasheet says 0; it's wrong */
-       }
-
-       ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-       ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-       ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-       ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-       return 0;
-}
-
-static int ov6x30_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case OVCAMCHIP_CMD_S_CTRL:
-               return ov6x30_set_control(c, arg);
-       case OVCAMCHIP_CMD_G_CTRL:
-               return ov6x30_get_control(c, arg);
-       case OVCAMCHIP_CMD_S_MODE:
-               return ov6x30_set_window(c, arg);
-       default:
-               DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-               return -ENOIOCTLCMD;
-       }
-}
-
-struct ovcamchip_ops ov6x30_ops = {
-       .init    =      ov6x30_init,
-       .free    =      ov6x30_free,
-       .command =      ov6x30_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov76be.c b/drivers/media/video/ovcamchip/ov76be.c
deleted file mode 100644 (file)
index 11f6be9..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-/* OmniVision OV76BE Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* OV7610 registers: Since the OV76BE is undocumented, we'll settle for these
- * for now. */
-#define REG_GAIN               0x00    /* gain [5:0] */
-#define REG_BLUE               0x01    /* blue channel balance */
-#define REG_RED                        0x02    /* red channel balance */
-#define REG_SAT                        0x03    /* saturation */
-#define REG_CNT                        0x05    /* Y contrast */
-#define REG_BRT                        0x06    /* Y brightness */
-#define REG_BLUE_BIAS          0x0C    /* blue channel bias [5:0] */
-#define REG_RED_BIAS           0x0D    /* red channel bias [5:0] */
-#define REG_GAMMA_COEFF                0x0E    /* gamma settings */
-#define REG_WB_RANGE           0x0F    /* AEC/ALC/S-AWB settings */
-#define REG_EXP                        0x10    /* manual exposure setting */
-#define REG_CLOCK              0x11    /* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE       0x16    /* field interval/mode settings */
-#define REG_HWIN_START         0x17    /* horizontal window start */
-#define REG_HWIN_END           0x18    /* horizontal window end */
-#define REG_VWIN_START         0x19    /* vertical window start */
-#define REG_VWIN_END           0x1A    /* vertical window end */
-#define REG_PIXEL_SHIFT        0x1B    /* pixel shift */
-#define REG_YOFFSET            0x21    /* Y channel offset */
-#define REG_UOFFSET            0x22    /* U channel offset */
-#define REG_ECW                        0x24    /* exposure white level for AEC */
-#define REG_ECB                        0x25    /* exposure black level for AEC */
-#define REG_FRAMERATE_H                0x2A    /* frame rate MSB + misc */
-#define REG_FRAMERATE_L                0x2B    /* frame rate LSB */
-#define REG_ALC                        0x2C    /* Auto Level Control settings */
-#define REG_VOFFSET            0x2E    /* V channel offset adjustment */
-#define REG_ARRAY_BIAS         0x2F    /* array bias -- don't change */
-#define REG_YGAMMA             0x33    /* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST                0x34    /* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov76be {
-       int auto_brt;
-       int auto_exp;
-       int bandfilt;
-       int mirror;
-};
-
-/* NOTE: These are the same as the 7x10 settings, but should eventually be
- * optimized for the OV76BE */
-static struct ovcamchip_regvals regvals_init_76be[] = {
-       { 0x10, 0xff },
-       { 0x16, 0x03 },
-       { 0x28, 0x24 },
-       { 0x2b, 0xac },
-       { 0x12, 0x00 },
-       { 0x38, 0x81 },
-       { 0x28, 0x24 }, /* 0c */
-       { 0x0f, 0x85 }, /* lg's setting */
-       { 0x15, 0x01 },
-       { 0x20, 0x1c },
-       { 0x23, 0x2a },
-       { 0x24, 0x10 },
-       { 0x25, 0x8a },
-       { 0x26, 0xa2 },
-       { 0x27, 0xc2 },
-       { 0x2a, 0x04 },
-       { 0x2c, 0xfe },
-       { 0x2d, 0x93 },
-       { 0x30, 0x71 },
-       { 0x31, 0x60 },
-       { 0x32, 0x26 },
-       { 0x33, 0x20 },
-       { 0x34, 0x48 },
-       { 0x12, 0x24 },
-       { 0x11, 0x01 },
-       { 0x0c, 0x24 },
-       { 0x0d, 0x24 },
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV76be camera chip and relevant variables. */
-static int ov76be_init(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov76be *s;
-       int rc;
-
-       DDEBUG(4, &c->dev, "entered");
-
-       rc = ov_write_regvals(c, regvals_init_76be);
-       if (rc < 0)
-               return rc;
-
-       ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
-
-       s->auto_brt = 1;
-       s->auto_exp = 1;
-
-       return rc;
-}
-
-static int ov76be_free(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-
-       kfree(ov->spriv);
-       return 0;
-}
-
-static int ov76be_set_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov76be *s = ov->spriv;
-       int rc;
-       int v = ctl->value;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_write(c, REG_BRT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_write(c, REG_SAT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_write(c, REG_EXP, v);
-               break;
-       case OVCAMCHIP_CID_FREQ:
-       {
-               int sixty = (v == 60);
-
-               rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, 0x2b, sixty?0x00:0xac);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x76, 0x01, 0x01);
-               break;
-       }
-       case OVCAMCHIP_CID_BANDFILT:
-               rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-               s->bandfilt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-               s->auto_brt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
-               s->auto_exp = v;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-               s->mirror = v;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-out:
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-       return rc;
-}
-
-static int ov76be_get_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov76be *s = ov->spriv;
-       int rc = 0;
-       unsigned char val = 0;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_read(c, REG_BRT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_read(c, REG_SAT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_read(c, REG_EXP, &val);
-               ctl->value = val;
-               break;
-       case OVCAMCHIP_CID_BANDFILT:
-               ctl->value = s->bandfilt;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               ctl->value = s->auto_brt;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               ctl->value = s->auto_exp;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               ctl->value = s->mirror;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-       return rc;
-}
-
-static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int qvga = win->quarter;
-
-       /******** QVGA-specific regs ********/
-
-       ov_write(c, 0x14, qvga?0xa4:0x84);
-
-       /******** Palette-specific regs ********/
-
-       if (win->format == VIDEO_PALETTE_GREY) {
-               ov_write_mask(c, 0x0e, 0x40, 0x40);
-               ov_write_mask(c, 0x13, 0x20, 0x20);
-       } else {
-               ov_write_mask(c, 0x0e, 0x00, 0x40);
-               ov_write_mask(c, 0x13, 0x00, 0x20);
-       }
-
-       /******** Clock programming ********/
-
-       ov_write(c, 0x11, win->clockdiv);
-
-       /******** Resolution-specific ********/
-
-       if (win->width == 640 && win->height == 480)
-               ov_write(c, 0x35, 0x9e);
-       else
-               ov_write(c, 0x35, 0x1e);
-
-       return 0;
-}
-
-static int ov76be_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int ret, hwscale, vwscale;
-
-       ret = ov76be_mode_init(c, win);
-       if (ret < 0)
-               return ret;
-
-       if (win->quarter) {
-               hwscale = 1;
-               vwscale = 0;
-       } else {
-               hwscale = 2;
-               vwscale = 1;
-       }
-
-       ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-       ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-       ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-       ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-       return 0;
-}
-
-static int ov76be_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case OVCAMCHIP_CMD_S_CTRL:
-               return ov76be_set_control(c, arg);
-       case OVCAMCHIP_CMD_G_CTRL:
-               return ov76be_get_control(c, arg);
-       case OVCAMCHIP_CMD_S_MODE:
-               return ov76be_set_window(c, arg);
-       default:
-               DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-               return -ENOIOCTLCMD;
-       }
-}
-
-struct ovcamchip_ops ov76be_ops = {
-       .init    =      ov76be_init,
-       .free    =      ov76be_free,
-       .command =      ov76be_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x10.c b/drivers/media/video/ovcamchip/ov7x10.c
deleted file mode 100644 (file)
index 5206e79..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/* OmniVision OV7610/OV7110 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- *
- * This program is free software; 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN               0x00    /* gain [5:0] */
-#define REG_BLUE               0x01    /* blue channel balance */
-#define REG_RED                        0x02    /* red channel balance */
-#define REG_SAT                        0x03    /* saturation */
-#define REG_CNT                        0x05    /* Y contrast */
-#define REG_BRT                        0x06    /* Y brightness */
-#define REG_BLUE_BIAS          0x0C    /* blue channel bias [5:0] */
-#define REG_RED_BIAS           0x0D    /* red channel bias [5:0] */
-#define REG_GAMMA_COEFF                0x0E    /* gamma settings */
-#define REG_WB_RANGE           0x0F    /* AEC/ALC/S-AWB settings */
-#define REG_EXP                        0x10    /* manual exposure setting */
-#define REG_CLOCK              0x11    /* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE       0x16    /* field interval/mode settings */
-#define REG_HWIN_START         0x17    /* horizontal window start */
-#define REG_HWIN_END           0x18    /* horizontal window end */
-#define REG_VWIN_START         0x19    /* vertical window start */
-#define REG_VWIN_END           0x1A    /* vertical window end */
-#define REG_PIXEL_SHIFT        0x1B    /* pixel shift */
-#define REG_YOFFSET            0x21    /* Y channel offset */
-#define REG_UOFFSET            0x22    /* U channel offset */
-#define REG_ECW                        0x24    /* exposure white level for AEC */
-#define REG_ECB                        0x25    /* exposure black level for AEC */
-#define REG_FRAMERATE_H                0x2A    /* frame rate MSB + misc */
-#define REG_FRAMERATE_L                0x2B    /* frame rate LSB */
-#define REG_ALC                        0x2C    /* Auto Level Control settings */
-#define REG_VOFFSET            0x2E    /* V channel offset adjustment */
-#define REG_ARRAY_BIAS         0x2F    /* array bias -- don't change */
-#define REG_YGAMMA             0x33    /* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST                0x34    /* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x10 {
-       int auto_brt;
-       int auto_exp;
-       int bandfilt;
-       int mirror;
-};
-
-/* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- *     shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- *     contrast
- */
-static struct ovcamchip_regvals regvals_init_7x10[] = {
-       { 0x10, 0xff },
-       { 0x16, 0x03 },
-       { 0x28, 0x24 },
-       { 0x2b, 0xac },
-       { 0x12, 0x00 },
-       { 0x38, 0x81 },
-       { 0x28, 0x24 }, /* 0c */
-       { 0x0f, 0x85 }, /* lg's setting */
-       { 0x15, 0x01 },
-       { 0x20, 0x1c },
-       { 0x23, 0x2a },
-       { 0x24, 0x10 },
-       { 0x25, 0x8a },
-       { 0x26, 0xa2 },
-       { 0x27, 0xc2 },
-       { 0x2a, 0x04 },
-       { 0x2c, 0xfe },
-       { 0x2d, 0x93 },
-       { 0x30, 0x71 },
-       { 0x31, 0x60 },
-       { 0x32, 0x26 },
-       { 0x33, 0x20 },
-       { 0x34, 0x48 },
-       { 0x12, 0x24 },
-       { 0x11, 0x01 },
-       { 0x0c, 0x24 },
-       { 0x0d, 0x24 },
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV7x10 camera chip and relevant variables. */
-static int ov7x10_init(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov7x10 *s;
-       int rc;
-
-       DDEBUG(4, &c->dev, "entered");
-
-       rc = ov_write_regvals(c, regvals_init_7x10);
-       if (rc < 0)
-               return rc;
-
-       ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
-
-       s->auto_brt = 1;
-       s->auto_exp = 1;
-
-       return rc;
-}
-
-static int ov7x10_free(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-
-       kfree(ov->spriv);
-       return 0;
-}
-
-static int ov7x10_set_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov7x10 *s = ov->spriv;
-       int rc;
-       int v = ctl->value;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_write(c, REG_CNT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_write(c, REG_BRT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_write(c, REG_SAT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_HUE:
-               rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, REG_BLUE, v >> 8);
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_write(c, REG_EXP, v);
-               break;
-       case OVCAMCHIP_CID_FREQ:
-       {
-               int sixty = (v == 60);
-
-               rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, 0x2b, sixty?0x00:0xac);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x13, 0x10, 0x10);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x13, 0x00, 0x10);
-               break;
-       }
-       case OVCAMCHIP_CID_BANDFILT:
-               rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-               s->bandfilt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-               s->auto_brt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               rc = ov_write_mask(c, 0x29, v?0x00:0x80, 0x80);
-               s->auto_exp = v;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-               s->mirror = v;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-out:
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-       return rc;
-}
-
-static int ov7x10_get_control(struct i2c_client *c,
-                             struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov7x10 *s = ov->spriv;
-       int rc = 0;
-       unsigned char val = 0;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_read(c, REG_CNT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_read(c, REG_BRT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_read(c, REG_SAT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_HUE:
-               rc = ov_read(c, REG_BLUE, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_read(c, REG_EXP, &val);
-               ctl->value = val;
-               break;
-       case OVCAMCHIP_CID_BANDFILT:
-               ctl->value = s->bandfilt;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               ctl->value = s->auto_brt;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               ctl->value = s->auto_exp;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               ctl->value = s->mirror;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-       return rc;
-}
-
-static int ov7x10_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int qvga = win->quarter;
-
-       /******** QVGA-specific regs ********/
-
-       ov_write(c, 0x14, qvga?0x24:0x04);
-
-       /******** Palette-specific regs ********/
-
-       if (win->format == VIDEO_PALETTE_GREY) {
-               ov_write_mask(c, 0x0e, 0x40, 0x40);
-               ov_write_mask(c, 0x13, 0x20, 0x20);
-       } else {
-               ov_write_mask(c, 0x0e, 0x00, 0x40);
-               ov_write_mask(c, 0x13, 0x00, 0x20);
-       }
-
-       /******** Clock programming ********/
-
-       ov_write(c, 0x11, win->clockdiv);
-
-       /******** Resolution-specific ********/
-
-       if (win->width == 640 && win->height == 480)
-               ov_write(c, 0x35, 0x9e);
-       else
-               ov_write(c, 0x35, 0x1e);
-
-       return 0;
-}
-
-static int ov7x10_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int ret, hwscale, vwscale;
-
-       ret = ov7x10_mode_init(c, win);
-       if (ret < 0)
-               return ret;
-
-       if (win->quarter) {
-               hwscale = 1;
-               vwscale = 0;
-       } else {
-               hwscale = 2;
-               vwscale = 1;
-       }
-
-       ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-       ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-       ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-       ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-       return 0;
-}
-
-static int ov7x10_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case OVCAMCHIP_CMD_S_CTRL:
-               return ov7x10_set_control(c, arg);
-       case OVCAMCHIP_CMD_G_CTRL:
-               return ov7x10_get_control(c, arg);
-       case OVCAMCHIP_CMD_S_MODE:
-               return ov7x10_set_window(c, arg);
-       default:
-               DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-               return -ENOIOCTLCMD;
-       }
-}
-
-struct ovcamchip_ops ov7x10_ops = {
-       .init    =      ov7x10_init,
-       .free    =      ov7x10_free,
-       .command =      ov7x10_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x20.c b/drivers/media/video/ovcamchip/ov7x20.c
deleted file mode 100644 (file)
index 8e26ae3..0000000
+++ /dev/null
@@ -1,454 +0,0 @@
-/* OmniVision OV7620/OV7120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN               0x00    /* gain [5:0] */
-#define REG_BLUE               0x01    /* blue gain */
-#define REG_RED                        0x02    /* red gain */
-#define REG_SAT                        0x03    /* saturation */
-#define REG_BRT                        0x06    /* Y brightness */
-#define REG_SHARP              0x07    /* analog sharpness */
-#define REG_BLUE_BIAS          0x0C    /* WB blue ratio [5:0] */
-#define REG_RED_BIAS           0x0D    /* WB red ratio [5:0] */
-#define REG_EXP                        0x10    /* exposure */
-
-/* Default control settings. Values are in terms of V4L2 controls. */
-#define OV7120_DFL_BRIGHT     0x60
-#define OV7620_DFL_BRIGHT     0x60
-#define OV7120_DFL_SAT        0xb0
-#define OV7620_DFL_SAT        0xc0
-#define DFL_AUTO_EXP             1
-#define DFL_AUTO_GAIN            1
-#define OV7120_DFL_GAIN       0x00
-#define OV7620_DFL_GAIN       0x00
-/* NOTE: Since autoexposure is the default, these aren't programmed into the
- * OV7x20 chip. They are just here because V4L2 expects a default */
-#define OV7120_DFL_EXP        0x7f
-#define OV7620_DFL_EXP        0x7f
-
-/* Window parameters */
-#define HWSBASE 0x2F   /* From 7620.SET (spec is wrong) */
-#define HWEBASE 0x2F
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x20 {
-       int auto_brt;
-       int auto_exp;
-       int auto_gain;
-       int backlight;
-       int bandfilt;
-       int mirror;
-};
-
-/* Contrast look-up table */
-static unsigned char ctab[] = {
-       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
-       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-};
-
-/* Settings for (Black & White) OV7120 camera chip */
-static struct ovcamchip_regvals regvals_init_7120[] = {
-       { 0x12, 0x80 }, /* reset */
-       { 0x13, 0x00 }, /* Autoadjust off */
-       { 0x12, 0x20 }, /* Disable AWB */
-       { 0x13, DFL_AUTO_GAIN?0x01:0x00 }, /* Autoadjust on (if desired) */
-       { 0x00, OV7120_DFL_GAIN },
-       { 0x01, 0x80 },
-       { 0x02, 0x80 },
-       { 0x03, OV7120_DFL_SAT },
-       { 0x06, OV7120_DFL_BRIGHT },
-       { 0x07, 0x00 },
-       { 0x0c, 0x20 },
-       { 0x0d, 0x20 },
-       { 0x11, 0x01 },
-       { 0x14, 0x84 },
-       { 0x15, 0x01 },
-       { 0x16, 0x03 },
-       { 0x17, 0x2f },
-       { 0x18, 0xcf },
-       { 0x19, 0x06 },
-       { 0x1a, 0xf5 },
-       { 0x1b, 0x00 },
-       { 0x20, 0x08 },
-       { 0x21, 0x80 },
-       { 0x22, 0x80 },
-       { 0x23, 0x00 },
-       { 0x26, 0xa0 },
-       { 0x27, 0xfa },
-       { 0x28, 0x20 }, /* DON'T set bit 6. It is for the OV7620 only */
-       { 0x29, DFL_AUTO_EXP?0x00:0x80 },
-       { 0x2a, 0x10 },
-       { 0x2b, 0x00 },
-       { 0x2c, 0x88 },
-       { 0x2d, 0x95 },
-       { 0x2e, 0x80 },
-       { 0x2f, 0x44 },
-       { 0x60, 0x20 },
-       { 0x61, 0x02 },
-       { 0x62, 0x5f },
-       { 0x63, 0xd5 },
-       { 0x64, 0x57 },
-       { 0x65, 0x83 }, /* OV says "don't change this value" */
-       { 0x66, 0x55 },
-       { 0x67, 0x92 },
-       { 0x68, 0xcf },
-       { 0x69, 0x76 },
-       { 0x6a, 0x22 },
-       { 0x6b, 0xe2 },
-       { 0x6c, 0x40 },
-       { 0x6d, 0x48 },
-       { 0x6e, 0x80 },
-       { 0x6f, 0x0d },
-       { 0x70, 0x89 },
-       { 0x71, 0x00 },
-       { 0x72, 0x14 },
-       { 0x73, 0x54 },
-       { 0x74, 0xa0 },
-       { 0x75, 0x8e },
-       { 0x76, 0x00 },
-       { 0x77, 0xff },
-       { 0x78, 0x80 },
-       { 0x79, 0x80 },
-       { 0x7a, 0x80 },
-       { 0x7b, 0xe6 },
-       { 0x7c, 0x00 },
-       { 0x24, 0x3a },
-       { 0x25, 0x60 },
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Settings for (color) OV7620 camera chip */
-static struct ovcamchip_regvals regvals_init_7620[] = {
-       { 0x12, 0x80 }, /* reset */
-       { 0x00, OV7620_DFL_GAIN },
-       { 0x01, 0x80 },
-       { 0x02, 0x80 },
-       { 0x03, OV7620_DFL_SAT },
-       { 0x06, OV7620_DFL_BRIGHT },
-       { 0x07, 0x00 },
-       { 0x0c, 0x24 },
-       { 0x0c, 0x24 },
-       { 0x0d, 0x24 },
-       { 0x11, 0x01 },
-       { 0x12, 0x24 },
-       { 0x13, DFL_AUTO_GAIN?0x01:0x00 },
-       { 0x14, 0x84 },
-       { 0x15, 0x01 },
-       { 0x16, 0x03 },
-       { 0x17, 0x2f },
-       { 0x18, 0xcf },
-       { 0x19, 0x06 },
-       { 0x1a, 0xf5 },
-       { 0x1b, 0x00 },
-       { 0x20, 0x18 },
-       { 0x21, 0x80 },
-       { 0x22, 0x80 },
-       { 0x23, 0x00 },
-       { 0x26, 0xa2 },
-       { 0x27, 0xea },
-       { 0x28, 0x20 },
-       { 0x29, DFL_AUTO_EXP?0x00:0x80 },
-       { 0x2a, 0x10 },
-       { 0x2b, 0x00 },
-       { 0x2c, 0x88 },
-       { 0x2d, 0x91 },
-       { 0x2e, 0x80 },
-       { 0x2f, 0x44 },
-       { 0x60, 0x27 },
-       { 0x61, 0x02 },
-       { 0x62, 0x5f },
-       { 0x63, 0xd5 },
-       { 0x64, 0x57 },
-       { 0x65, 0x83 },
-       { 0x66, 0x55 },
-       { 0x67, 0x92 },
-       { 0x68, 0xcf },
-       { 0x69, 0x76 },
-       { 0x6a, 0x22 },
-       { 0x6b, 0x00 },
-       { 0x6c, 0x02 },
-       { 0x6d, 0x44 },
-       { 0x6e, 0x80 },
-       { 0x6f, 0x1d },
-       { 0x70, 0x8b },
-       { 0x71, 0x00 },
-       { 0x72, 0x14 },
-       { 0x73, 0x54 },
-       { 0x74, 0x00 },
-       { 0x75, 0x8e },
-       { 0x76, 0x00 },
-       { 0x77, 0xff },
-       { 0x78, 0x80 },
-       { 0x79, 0x80 },
-       { 0x7a, 0x80 },
-       { 0x7b, 0xe2 },
-       { 0x7c, 0x00 },
-       { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Returns index into the specified look-up table, with 'n' elements, for which
- * the value is greater than or equal to "val". If a match isn't found, (n-1)
- * is returned. The entries in the table must be in ascending order. */
-static inline int ov7x20_lut_find(unsigned char lut[], int n, unsigned char val)
-{
-       int i = 0;
-
-       while (lut[i] < val && i < n)
-               i++;
-
-       return i;
-}
-
-/* This initializes the OV7x20 camera chip and relevant variables. */
-static int ov7x20_init(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov7x20 *s;
-       int rc;
-
-       DDEBUG(4, &c->dev, "entered");
-
-       if (ov->mono)
-               rc = ov_write_regvals(c, regvals_init_7120);
-       else
-               rc = ov_write_regvals(c, regvals_init_7620);
-
-       if (rc < 0)
-               return rc;
-
-       ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
-
-       s->auto_brt = 1;
-       s->auto_exp = DFL_AUTO_EXP;
-       s->auto_gain = DFL_AUTO_GAIN;
-
-       return 0;
-}
-
-static int ov7x20_free(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-
-       kfree(ov->spriv);
-       return 0;
-}
-
-static int ov7x20_set_v4l1_control(struct i2c_client *c,
-                                  struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov7x20 *s = ov->spriv;
-       int rc;
-       int v = ctl->value;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-       {
-               /* Use Y gamma control instead. Bit 0 enables it. */
-               rc = ov_write(c, 0x64, ctab[v >> 12]);
-               break;
-       }
-       case OVCAMCHIP_CID_BRIGHT:
-               /* 7620 doesn't like manual changes when in auto mode */
-               if (!s->auto_brt)
-                       rc = ov_write(c, REG_BRT, v >> 8);
-               else
-                       rc = 0;
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_write(c, REG_SAT, v >> 8);
-               break;
-       case OVCAMCHIP_CID_EXP:
-               if (!s->auto_exp)
-                       rc = ov_write(c, REG_EXP, v);
-               else
-                       rc = -EBUSY;
-               break;
-       case OVCAMCHIP_CID_FREQ:
-       {
-               int sixty = (v == 60);
-
-               rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write(c, 0x2b, sixty?0x00:0xac);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x76, 0x01, 0x01);
-               break;
-       }
-       case OVCAMCHIP_CID_BANDFILT:
-               rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-               s->bandfilt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-               s->auto_brt = v;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
-               s->auto_exp = v;
-               break;
-       case OVCAMCHIP_CID_BACKLIGHT:
-       {
-               rc = ov_write_mask(c, 0x68, v?0xe0:0xc0, 0xe0);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
-               if (rc < 0)
-                       goto out;
-
-               rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
-               s->backlight = v;
-               break;
-       }
-       case OVCAMCHIP_CID_MIRROR:
-               rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-               s->mirror = v;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-out:
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-       return rc;
-}
-
-static int ov7x20_get_v4l1_control(struct i2c_client *c,
-                                  struct ovcamchip_control *ctl)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       struct ov7x20 *s = ov->spriv;
-       int rc = 0;
-       unsigned char val = 0;
-
-       switch (ctl->id) {
-       case OVCAMCHIP_CID_CONT:
-               rc = ov_read(c, 0x64, &val);
-               ctl->value = ov7x20_lut_find(ctab, 16, val) << 12;
-               break;
-       case OVCAMCHIP_CID_BRIGHT:
-               rc = ov_read(c, REG_BRT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_SAT:
-               rc = ov_read(c, REG_SAT, &val);
-               ctl->value = val << 8;
-               break;
-       case OVCAMCHIP_CID_EXP:
-               rc = ov_read(c, REG_EXP, &val);
-               ctl->value = val;
-               break;
-       case OVCAMCHIP_CID_BANDFILT:
-               ctl->value = s->bandfilt;
-               break;
-       case OVCAMCHIP_CID_AUTOBRIGHT:
-               ctl->value = s->auto_brt;
-               break;
-       case OVCAMCHIP_CID_AUTOEXP:
-               ctl->value = s->auto_exp;
-               break;
-       case OVCAMCHIP_CID_BACKLIGHT:
-               ctl->value = s->backlight;
-               break;
-       case OVCAMCHIP_CID_MIRROR:
-               ctl->value = s->mirror;
-               break;
-       default:
-               DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-               return -EPERM;
-       }
-
-       DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-       return rc;
-}
-
-static int ov7x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       int qvga = win->quarter;
-
-       /******** QVGA-specific regs ********/
-       ov_write_mask(c, 0x14, qvga?0x20:0x00, 0x20);
-       ov_write_mask(c, 0x28, qvga?0x00:0x20, 0x20);
-       ov_write(c, 0x24, qvga?0x20:0x3a);
-       ov_write(c, 0x25, qvga?0x30:0x60);
-       ov_write_mask(c, 0x2d, qvga?0x40:0x00, 0x40);
-       if (!ov->mono)
-               ov_write_mask(c, 0x67, qvga?0xf0:0x90, 0xf0);
-       ov_write_mask(c, 0x74, qvga?0x20:0x00, 0x20);
-
-       /******** Clock programming ********/
-
-       ov_write(c, 0x11, win->clockdiv);
-
-       return 0;
-}
-
-static int ov7x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-       int ret, hwscale, vwscale;
-
-       ret = ov7x20_mode_init(c, win);
-       if (ret < 0)
-               return ret;
-
-       if (win->quarter) {
-               hwscale = 1;
-               vwscale = 0;
-       } else {
-               hwscale = 2;
-               vwscale = 1;
-       }
-
-       ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-       ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-       ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-       ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-       return 0;
-}
-
-static int ov7x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case OVCAMCHIP_CMD_S_CTRL:
-               return ov7x20_set_v4l1_control(c, arg);
-       case OVCAMCHIP_CMD_G_CTRL:
-               return ov7x20_get_v4l1_control(c, arg);
-       case OVCAMCHIP_CMD_S_MODE:
-               return ov7x20_set_window(c, arg);
-       default:
-               DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-               return -ENOIOCTLCMD;
-       }
-}
-
-struct ovcamchip_ops ov7x20_ops = {
-       .init    =      ov7x20_init,
-       .free    =      ov7x20_free,
-       .command =      ov7x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
deleted file mode 100644 (file)
index d573d84..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/* Shared Code for OmniVision Camera Chip Drivers
- *
- * Copyright (c) 2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
-#include "ovcamchip_priv.h"
-
-#define DRIVER_VERSION "v2.27 for Linux 2.6"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org>"
-#define DRIVER_DESC "OV camera chip I2C driver"
-
-#define PINFO(fmt, args...) printk(KERN_INFO "ovcamchip: " fmt "\n" , ## args);
-#define PERROR(fmt, args...) printk(KERN_ERR "ovcamchip: " fmt "\n" , ## args);
-
-#ifdef DEBUG
-int ovcamchip_debug = 0;
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
-  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=all");
-#endif
-
-/* By default, let bridge driver tell us if chip is monochrome. mono=0
- * will ignore that and always treat chips as color. mono=1 will force
- * monochrome mode for all chips. */
-static int mono = -1;
-module_param(mono, int, 0);
-MODULE_PARM_DESC(mono,
-  "1=chips are monochrome (OVx1xx), 0=force color, -1=autodetect (default)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-
-/* Registers common to all chips, that are needed for detection */
-#define GENERIC_REG_ID_HIGH       0x1C /* manufacturer ID MSB */
-#define GENERIC_REG_ID_LOW        0x1D /* manufacturer ID LSB */
-#define GENERIC_REG_COM_I         0x29 /* misc ID bits */
-
-static char *chip_names[NUM_CC_TYPES] = {
-       [CC_UNKNOWN]    = "Unknown chip",
-       [CC_OV76BE]     = "OV76BE",
-       [CC_OV7610]     = "OV7610",
-       [CC_OV7620]     = "OV7620",
-       [CC_OV7620AE]   = "OV7620AE",
-       [CC_OV6620]     = "OV6620",
-       [CC_OV6630]     = "OV6630",
-       [CC_OV6630AE]   = "OV6630AE",
-       [CC_OV6630AF]   = "OV6630AF",
-};
-
-/* ----------------------------------------------------------------------- */
-
-int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
-{
-       int rc;
-
-       while (rvals->reg != 0xff) {
-               rc = ov_write(c, rvals->reg, rvals->val);
-               if (rc < 0)
-                       return rc;
-               rvals++;
-       }
-
-       return 0;
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-int ov_write_mask(struct i2c_client *c,
-                 unsigned char reg,
-                 unsigned char value,
-                 unsigned char mask)
-{
-       int rc;
-       unsigned char oldval, newval;
-
-       if (mask == 0xff) {
-               newval = value;
-       } else {
-               rc = ov_read(c, reg, &oldval);
-               if (rc < 0)
-                       return rc;
-
-               oldval &= (~mask);              /* Clear the masked bits */
-               value &= mask;                  /* Enforce mask on value */
-               newval = oldval | value;        /* Set the desired bits */
-       }
-
-       return ov_write(c, reg, newval);
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* Reset the chip and ensure that I2C is synchronized. Returns <0 if failure.
- */
-static int init_camchip(struct i2c_client *c)
-{
-       int i, success;
-       unsigned char high, low;
-
-       /* Reset the chip */
-       ov_write(c, 0x12, 0x80);
-
-       /* Wait for it to initialize */
-       msleep(150);
-
-       for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
-               if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
-                       if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) {
-                               if (high == 0x7F && low == 0xA2) {
-                                       success = 1;
-                                       continue;
-                               }
-                       }
-               }
-
-               /* Reset the chip */
-               ov_write(c, 0x12, 0x80);
-
-               /* Wait for it to initialize */
-               msleep(150);
-
-               /* Dummy read to sync I2C */
-               ov_read(c, 0x00, &low);
-       }
-
-       if (!success)
-               return -EIO;
-
-       PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
-       return 0;
-}
-
-/* This detects the OV7610, OV7620, or OV76BE chip. */
-static int ov7xx0_detect(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       int rc;
-       unsigned char val;
-
-       PDEBUG(4, "");
-
-       /* Detect chip (sub)type */
-       rc = ov_read(c, GENERIC_REG_COM_I, &val);
-       if (rc < 0) {
-               PERROR("Error detecting ov7xx0 type");
-               return rc;
-       }
-
-       if ((val & 3) == 3) {
-               PINFO("Camera chip is an OV7610");
-               ov->subtype = CC_OV7610;
-       } else if ((val & 3) == 1) {
-               rc = ov_read(c, 0x15, &val);
-               if (rc < 0) {
-                       PERROR("Error detecting ov7xx0 type");
-                       return rc;
-               }
-
-               if (val & 1) {
-                       PINFO("Camera chip is an OV7620AE");
-                       /* OV7620 is a close enough match for now. There are
-                        * some definite differences though, so this should be
-                        * fixed */
-                       ov->subtype = CC_OV7620;
-               } else {
-                       PINFO("Camera chip is an OV76BE");
-                       ov->subtype = CC_OV76BE;
-               }
-       } else if ((val & 3) == 0) {
-               PINFO("Camera chip is an OV7620");
-               ov->subtype = CC_OV7620;
-       } else {
-               PERROR("Unknown camera chip version: %d", val & 3);
-               return -ENOSYS;
-       }
-
-       if (ov->subtype == CC_OV76BE)
-               ov->sops = &ov76be_ops;
-       else if (ov->subtype == CC_OV7620)
-               ov->sops = &ov7x20_ops;
-       else
-               ov->sops = &ov7x10_ops;
-
-       return 0;
-}
-
-/* This detects the OV6620, OV6630, OV6630AE, or OV6630AF chip. */
-static int ov6xx0_detect(struct i2c_client *c)
-{
-       struct ovcamchip *ov = i2c_get_clientdata(c);
-       int rc;
-       unsigned char val;
-
-       PDEBUG(4, "");
-
-       /* Detect chip (sub)type */
-       rc = ov_read(c, GENERIC_REG_COM_I, &val);
-       if (rc < 0) {
-               PERROR("Error detecting ov6xx0 type");
-               return -1;
-       }
-
-       if ((val & 3) == 0) {
-               ov->subtype = CC_OV6630;
-               PINFO("Camera chip is an OV6630");
-       } else if ((val & 3) == 1) {
-               ov->subtype = CC_OV6620;
-               PINFO("Camera chip is an OV6620");
-       } else if ((val & 3) == 2) {
-               ov->subtype = CC_OV6630;
-               PINFO("Camera chip is an OV6630AE");
-       } else if ((val & 3) == 3) {
-               ov->subtype = CC_OV6630;
-               PINFO("Camera chip is an OV6630AF");
-       }
-
-       if (ov->subtype == CC_OV6620)
-               ov->sops = &ov6x20_ops;
-       else
-               ov->sops = &ov6x30_ops;
-
-       return 0;
-}
-
-static int ovcamchip_detect(struct i2c_client *c)
-{
-       /* Ideally we would just try a single register write and see if it NAKs.
-        * That isn't possible since the OV518 can't report I2C transaction
-        * failures. So, we have to try to initialize the chip (i.e. reset it
-        * and check the ID registers) to detect its presence. */
-
-       /* Test for 7xx0 */
-       PDEBUG(3, "Testing for 0V7xx0");
-       if (init_camchip(c) < 0)
-               return -ENODEV;
-       /* 7-bit addresses with bit 0 set are for the OV7xx0 */
-       if (c->addr & 1) {
-               if (ov7xx0_detect(c) < 0) {
-                       PERROR("Failed to init OV7xx0");
-                       return -EIO;
-               }
-               return 0;
-       }
-       /* Test for 6xx0 */
-       PDEBUG(3, "Testing for 0V6xx0");
-       if (ov6xx0_detect(c) < 0) {
-               PERROR("Failed to init OV6xx0");
-               return -EIO;
-       }
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-       struct ovcamchip *ov = to_ovcamchip(sd);
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-
-       if (!ov->initialized &&
-           cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
-           cmd != OVCAMCHIP_CMD_INITIALIZE) {
-               v4l2_err(sd, "Camera chip not initialized yet!\n");
-               return -EPERM;
-       }
-
-       switch (cmd) {
-       case OVCAMCHIP_CMD_Q_SUBTYPE:
-       {
-               *(int *)arg = ov->subtype;
-               return 0;
-       }
-       case OVCAMCHIP_CMD_INITIALIZE:
-       {
-               int rc;
-
-               if (mono == -1)
-                       ov->mono = *(int *)arg;
-               else
-                       ov->mono = mono;
-
-               if (ov->mono) {
-                       if (ov->subtype != CC_OV7620)
-                               v4l2_warn(sd, "Monochrome not "
-                                       "implemented for this chip\n");
-                       else
-                               v4l2_info(sd, "Initializing chip as "
-                                       "monochrome\n");
-               }
-
-               rc = ov->sops->init(c);
-               if (rc < 0)
-                       return rc;
-
-               ov->initialized = 1;
-               return 0;
-       }
-       default:
-               return ov->sops->command(c, cmd, arg);
-       }
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
-       .ioctl = ovcamchip_ioctl,
-};
-
-static const struct v4l2_subdev_ops ovcamchip_ops = {
-       .core = &ovcamchip_core_ops,
-};
-
-static int ovcamchip_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct ovcamchip *ov;
-       struct v4l2_subdev *sd;
-       int rc = 0;
-
-       ov = kzalloc(sizeof *ov, GFP_KERNEL);
-       if (!ov) {
-               rc = -ENOMEM;
-               goto no_ov;
-       }
-       sd = &ov->sd;
-       v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
-
-       rc = ovcamchip_detect(client);
-       if (rc < 0)
-               goto error;
-
-       v4l_info(client, "%s found @ 0x%02x (%s)\n",
-                       chip_names[ov->subtype], client->addr << 1, client->adapter->name);
-
-       PDEBUG(1, "Camera chip detection complete");
-
-       return rc;
-error:
-       kfree(ov);
-no_ov:
-       PDEBUG(1, "returning %d", rc);
-       return rc;
-}
-
-static int ovcamchip_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ovcamchip *ov = to_ovcamchip(sd);
-       int rc;
-
-       v4l2_device_unregister_subdev(sd);
-       rc = ov->sops->free(client);
-       if (rc < 0)
-               return rc;
-
-       kfree(ov);
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id ovcamchip_id[] = {
-       { "ovcamchip", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-       .name = "ovcamchip",
-       .probe = ovcamchip_probe,
-       .remove = ovcamchip_remove,
-       .id_table = ovcamchip_id,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
deleted file mode 100644 (file)
index 4f07b78..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* OmniVision* camera chip driver private definitions for core code and
- * chip-specific code
- *
- * Copyright (c) 1999-2004 Mark McClelland
- *
- * This program is free software; 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. NO WARRANTY OF ANY KIND is expressed or implied.
- *
- * * OmniVision is a trademark of OmniVision Technologies, Inc. This driver
- * is not sponsored or developed by them.
- */
-
-#ifndef __LINUX_OVCAMCHIP_PRIV_H
-#define __LINUX_OVCAMCHIP_PRIV_H
-
-#include <linux/i2c.h>
-#include <media/v4l2-subdev.h>
-#include <media/ovcamchip.h>
-
-#ifdef DEBUG
-extern int ovcamchip_debug;
-#endif
-
-#define PDEBUG(level, fmt, args...) \
-       if (ovcamchip_debug >= (level)) pr_debug("[%s:%d] " fmt "\n", \
-               __func__, __LINE__ , ## args)
-
-#define DDEBUG(level, dev, fmt, args...) \
-       if (ovcamchip_debug >= (level)) dev_dbg(dev, "[%s:%d] " fmt "\n", \
-               __func__, __LINE__ , ## args)
-
-/* Number of times to retry chip detection. Increase this if you are getting
- * "Failed to init camera chip" */
-#define I2C_DETECT_RETRIES     10
-
-struct ovcamchip_regvals {
-       unsigned char reg;
-       unsigned char val;
-};
-
-struct ovcamchip_ops {
-       int (*init)(struct i2c_client *);
-       int (*free)(struct i2c_client *);
-       int (*command)(struct i2c_client *, unsigned int, void *);
-};
-
-struct ovcamchip {
-       struct v4l2_subdev sd;
-       struct ovcamchip_ops *sops;
-       void *spriv;               /* Private data for OV7x10.c etc... */
-       int subtype;               /* = SEN_OV7610 etc... */
-       int mono;                  /* Monochrome chip? (invalid until init) */
-       int initialized;           /* OVCAMCHIP_CMD_INITIALIZE was successful */
-};
-
-static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
-{
-       return container_of(sd, struct ovcamchip, sd);
-}
-
-extern struct ovcamchip_ops ov6x20_ops;
-extern struct ovcamchip_ops ov6x30_ops;
-extern struct ovcamchip_ops ov7x10_ops;
-extern struct ovcamchip_ops ov7x20_ops;
-extern struct ovcamchip_ops ov76be_ops;
-
-/* --------------------------------- */
-/*              I2C I/O              */
-/* --------------------------------- */
-
-static inline int ov_read(struct i2c_client *c, unsigned char reg,
-                         unsigned char *value)
-{
-       int rc;
-
-       rc = i2c_smbus_read_byte_data(c, reg);
-       *value = (unsigned char) rc;
-       return rc;
-}
-
-static inline int ov_write(struct i2c_client *c, unsigned char reg,
-                          unsigned char value )
-{
-       return i2c_smbus_write_byte_data(c, reg, value);
-}
-
-/* --------------------------------- */
-/*        FUNCTION PROTOTYPES        */
-/* --------------------------------- */
-
-/* Functions in ovcamchip_core.c */
-
-extern int ov_write_regvals(struct i2c_client *c,
-                           struct ovcamchip_regvals *rvals);
-
-extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
-                        unsigned char value, unsigned char mask);
-
-#endif
index b4824782d858c9c8626c791405c822ba363e64af..bba6115c9ae88187be7edf0494e8911fd0754995 100644 (file)
@@ -223,7 +223,10 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
                                   " pvr2_ioread_setup (setup) id=%p",cp);
                        pvr2_stream_kill(sp);
                        ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
-                       if (ret < 0) return ret;
+                       if (ret < 0) {
+                               mutex_unlock(&cp->mutex);
+                               return ret;
+                       }
                        for (idx = 0; idx < BUFFER_COUNT; idx++) {
                                bp = pvr2_stream_get_buffer(sp,idx);
                                pvr2_buffer_set_buffer(bp,
index fb242f6cfb1f23b313df0ae80510ef8ec6042539..9de7d59916bda188c767d42f592f3d1f9b8b8d27 100644 (file)
@@ -276,7 +276,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
         * longer in STATE_QUEUED or STATE_ACTIVE
         */
        videobuf_waiton(&buf->vb, 0, 0);
-       videobuf_dma_unmap(vq, dma);
+       videobuf_dma_unmap(vq->dev, dma);
        videobuf_dma_free(dma);
 
        for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
@@ -1284,7 +1284,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
        }
 
        switch (code) {
-       case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
                formats++;
                if (xlate) {
                        xlate->host_fmt = &pxa_camera_formats[0];
@@ -1293,9 +1293,9 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
                        dev_dbg(dev, "Providing format %s using code %d\n",
                                pxa_camera_formats[0].name, code);
                }
-       case V4L2_MBUS_FMT_YVYU8_2X8_BE:
-       case V4L2_MBUS_FMT_YUYV8_2X8_LE:
-       case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
        case V4L2_MBUS_FMT_RGB565_2X8_LE:
        case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
                if (xlate)
index 47fd207ba3b1f63dd3edf9458ff0a7b98fa5f3b7..ce78fff234254b6fd535ef9fe7be0e3f253380a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Driver for RJ54N1CB0C CMOS Image Sensor from Micron
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
  *
  * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  *
@@ -127,8 +127,8 @@ static const struct rj54n1_datafmt *rj54n1_find_datafmt(
 }
 
 static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
-       {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
-       {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
@@ -1046,12 +1046,12 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
 
        /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
        switch (mf->code) {
-       case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
                ret = reg_write(client, RJ54N1_OUT_SEL, 0);
                if (!ret)
                        ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
                break;
-       case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
                ret = reg_write(client, RJ54N1_OUT_SEL, 0);
                if (!ret)
                        ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
index 3c7a79f3812a0f6a8cd94c5635301ac7ad96097e..8ec7c9a45a172ec2a62020de156d175e74891f36 100644 (file)
@@ -191,7 +191,6 @@ struct s2255_bufferi {
 struct s2255_dmaqueue {
        struct list_head        active;
        struct s2255_dev        *dev;
-       int                     channel;
 };
 
 /* for firmware loading, fw_state */
@@ -226,51 +225,60 @@ struct s2255_pipeinfo {
 };
 
 struct s2255_fmt; /*forward declaration */
+struct s2255_dev;
+
+struct s2255_channel {
+       struct video_device     vdev;
+       int                     resources;
+       struct s2255_dmaqueue   vidq;
+       struct s2255_bufferi    buffer;
+       struct s2255_mode       mode;
+       /* jpeg compression */
+       struct v4l2_jpegcompression jc;
+       /* capture parameters (for high quality mode full size) */
+       struct v4l2_captureparm cap_parm;
+       int                     cur_frame;
+       int                     last_frame;
+
+       int                     b_acquire;
+       /* allocated image size */
+       unsigned long           req_image_size;
+       /* received packet size */
+       unsigned long           pkt_size;
+       int                     bad_payload;
+       unsigned long           frame_count;
+       /* if JPEG image */
+       int                     jpg_size;
+       /* if channel configured to default state */
+       int                     configured;
+       wait_queue_head_t       wait_setmode;
+       int                     setmode_ready;
+       /* video status items */
+       int                     vidstatus;
+       wait_queue_head_t       wait_vidstatus;
+       int                     vidstatus_ready;
+       unsigned int            width;
+       unsigned int            height;
+       const struct s2255_fmt  *fmt;
+       int idx; /* channel number on device, 0-3 */
+};
+
 
 struct s2255_dev {
-       struct video_device     vdev[MAX_CHANNELS];
+       struct s2255_channel    channel[MAX_CHANNELS];
        struct v4l2_device      v4l2_dev;
-       atomic_t                channels; /* number of channels registered */
+       atomic_t                num_channels;
        int                     frames;
        struct mutex            lock;
        struct mutex            open_lock;
-       int                     resources[MAX_CHANNELS];
        struct usb_device       *udev;
        struct usb_interface    *interface;
        u8                      read_endpoint;
-
-       struct s2255_dmaqueue   vidq[MAX_CHANNELS];
        struct timer_list       timer;
        struct s2255_fw *fw_data;
        struct s2255_pipeinfo   pipe;
-       struct s2255_bufferi    buffer[MAX_CHANNELS];
-       struct s2255_mode       mode[MAX_CHANNELS];
-       /* jpeg compression */
-       struct v4l2_jpegcompression jc[MAX_CHANNELS];
-       /* capture parameters (for high quality mode full size) */
-       struct v4l2_captureparm cap_parm[MAX_CHANNELS];
-       const struct s2255_fmt  *cur_fmt[MAX_CHANNELS];
-       int                     cur_frame[MAX_CHANNELS];
-       int                     last_frame[MAX_CHANNELS];
        u32                     cc;     /* current channel */
-       int                     b_acquire[MAX_CHANNELS];
-       /* allocated image size */
-       unsigned long           req_image_size[MAX_CHANNELS];
-       /* received packet size */
-       unsigned long           pkt_size[MAX_CHANNELS];
-       int                     bad_payload[MAX_CHANNELS];
-       unsigned long           frame_count[MAX_CHANNELS];
        int                     frame_ready;
-       /* if JPEG image */
-       int                     jpg_size[MAX_CHANNELS];
-       /* if channel configured to default state */
-       int                     chn_configured[MAX_CHANNELS];
-       wait_queue_head_t       wait_setmode[MAX_CHANNELS];
-       int                     setmode_ready[MAX_CHANNELS];
-       /* video status items */
-       int                     vidstatus[MAX_CHANNELS];
-       wait_queue_head_t       wait_vidstatus[MAX_CHANNELS];
-       int                     vidstatus_ready[MAX_CHANNELS];
        int                     chn_ready;
        spinlock_t              slock;
        /* dsp firmware version (f2255usb.bin) */
@@ -298,16 +306,10 @@ struct s2255_buffer {
 
 struct s2255_fh {
        struct s2255_dev        *dev;
-       const struct s2255_fmt  *fmt;
-       unsigned int            width;
-       unsigned int            height;
        struct videobuf_queue   vb_vidq;
        enum v4l2_buf_type      type;
-       int                     channel;
-       /* mode below is the desired mode.
-          mode in s2255_dev is the current mode that was last set */
-       struct s2255_mode       mode;
-       int                     resources[MAX_CHANNELS];
+       struct s2255_channel    *channel;
+       int                     resources;
 };
 
 /* current cypress EEPROM firmware version */
@@ -360,12 +362,11 @@ static int *s2255_debug = &debug;
 
 static int s2255_start_readpipe(struct s2255_dev *dev);
 static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-                          int chn, int jpgsize);
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
-                         struct s2255_mode *mode);
+static int s2255_start_acquire(struct s2255_channel *channel);
+static int s2255_stop_acquire(struct s2255_channel *channel);
+static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+                          int jpgsize);
+static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
 static void s2255_fwload_start(struct s2255_dev *dev, int reset);
 static void s2255_destroy(struct s2255_dev *dev);
@@ -577,10 +578,11 @@ static void s2255_fwchunk_complete(struct urb *urb)
 
 }
 
-static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
+static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
 {
-       struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
+       struct s2255_dmaqueue *dma_q = &channel->vidq;
        struct s2255_buffer *buf;
+       struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
        unsigned long flags = 0;
        int rc = 0;
        spin_lock_irqsave(&dev->slock, flags);
@@ -593,7 +595,7 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
                         struct s2255_buffer, vb.queue);
        list_del(&buf->vb.queue);
        do_gettimeofday(&buf->vb.ts);
-       s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
+       s2255_fillbuff(channel, buf, jpgsize);
        wake_up(&buf->vb.done);
        dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
 unlock:
@@ -621,8 +623,8 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
  *                  http://v4l.videotechnology.com/
  *
  */
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-                          int chn, int jpgsize)
+static void s2255_fillbuff(struct s2255_channel *channel,
+                          struct s2255_buffer *buf, int jpgsize)
 {
        int pos = 0;
        struct timeval ts;
@@ -633,12 +635,11 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
 
        if (!vbuf)
                return;
-
-       last_frame = dev->last_frame[chn];
+       last_frame = channel->last_frame;
        if (last_frame != -1) {
-               frm = &dev->buffer[chn].frame[last_frame];
+               frm = &channel->buffer.frame[last_frame];
                tmpbuf =
-                   (const char *)dev->buffer[chn].frame[last_frame].lpvbits;
+                   (const char *)channel->buffer.frame[last_frame].lpvbits;
                switch (buf->fmt->fourcc) {
                case V4L2_PIX_FMT_YUYV:
                case V4L2_PIX_FMT_UYVY:
@@ -661,7 +662,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
                default:
                        printk(KERN_DEBUG "s2255: unknown format?\n");
                }
-               dev->last_frame[chn] = -1;
+               channel->last_frame = -1;
        } else {
                printk(KERN_ERR "s2255: =======no frame\n");
                return;
@@ -671,7 +672,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
                (unsigned long)vbuf, pos);
        /* tell v4l buffer was filled */
 
-       buf->vb.field_count = dev->frame_count[chn] * 2;
+       buf->vb.field_count = channel->frame_count * 2;
        do_gettimeofday(&ts);
        buf->vb.ts = ts;
        buf->vb.state = VIDEOBUF_DONE;
@@ -686,8 +687,8 @@ static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
                        unsigned int *size)
 {
        struct s2255_fh *fh = vq->priv_data;
-
-       *size = fh->width * fh->height * (fh->fmt->depth >> 3);
+       struct s2255_channel *channel = fh->channel;
+       *size = channel->width * channel->height * (channel->fmt->depth >> 3);
 
        if (0 == *count)
                *count = S2255_DEF_BUFS;
@@ -710,30 +711,31 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                          enum v4l2_field field)
 {
        struct s2255_fh *fh = vq->priv_data;
+       struct s2255_channel *channel = fh->channel;
        struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
        int rc;
+       int w = channel->width;
+       int h = channel->height;
        dprintk(4, "%s, field=%d\n", __func__, field);
-       if (fh->fmt == NULL)
+       if (channel->fmt == NULL)
                return -EINVAL;
 
-       if ((fh->width < norm_minw(&fh->dev->vdev[fh->channel])) ||
-           (fh->width > norm_maxw(&fh->dev->vdev[fh->channel])) ||
-           (fh->height < norm_minh(&fh->dev->vdev[fh->channel])) ||
-           (fh->height > norm_maxh(&fh->dev->vdev[fh->channel]))) {
+       if ((w < norm_minw(&channel->vdev)) ||
+           (w > norm_maxw(&channel->vdev)) ||
+           (h < norm_minh(&channel->vdev)) ||
+           (h > norm_maxh(&channel->vdev))) {
                dprintk(4, "invalid buffer prepare\n");
                return -EINVAL;
        }
-
-       buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3);
-
+       buf->vb.size = w * h * (channel->fmt->depth >> 3);
        if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
                dprintk(4, "invalid buffer prepare\n");
                return -EINVAL;
        }
 
-       buf->fmt = fh->fmt;
-       buf->vb.width = fh->width;
-       buf->vb.height = fh->height;
+       buf->fmt = channel->fmt;
+       buf->vb.width = w;
+       buf->vb.height = h;
        buf->vb.field = field;
 
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
@@ -753,8 +755,8 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
        struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
        struct s2255_fh *fh = vq->priv_data;
-       struct s2255_dev *dev = fh->dev;
-       struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
+       struct s2255_channel *channel = fh->channel;
+       struct s2255_dmaqueue *vidq = &channel->vidq;
        dprintk(1, "%s\n", __func__);
        buf->vb.state = VIDEOBUF_QUEUED;
        list_add_tail(&buf->vb.queue, &vidq->active);
@@ -765,7 +767,7 @@ static void buffer_release(struct videobuf_queue *vq,
 {
        struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
        struct s2255_fh *fh = vq->priv_data;
-       dprintk(4, "%s %d\n", __func__, fh->channel);
+       dprintk(4, "%s %d\n", __func__, fh->channel->idx);
        free_buffer(vq, buf);
 }
 
@@ -777,39 +779,43 @@ static struct videobuf_queue_ops s2255_video_qops = {
 };
 
 
-static int res_get(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_get(struct s2255_fh *fh)
 {
+       struct s2255_dev *dev = fh->dev;
        /* is it free? */
+       struct s2255_channel *channel = fh->channel;
        mutex_lock(&dev->lock);
-       if (dev->resources[fh->channel]) {
+       if (channel->resources) {
                /* no, someone else uses it */
                mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
-       dev->resources[fh->channel] = 1;
-       fh->resources[fh->channel] = 1;
+       channel->resources = 1;
+       fh->resources = 1;
        dprintk(1, "s2255: res: get\n");
        mutex_unlock(&dev->lock);
        return 1;
 }
 
-static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_locked(struct s2255_fh *fh)
 {
-       return dev->resources[fh->channel];
+       return fh->channel->resources;
 }
 
 static int res_check(struct s2255_fh *fh)
 {
-       return fh->resources[fh->channel];
+       return fh->resources;
 }
 
 
-static void res_free(struct s2255_dev *dev, struct s2255_fh *fh)
+static void res_free(struct s2255_fh *fh)
 {
+       struct s2255_channel *channel = fh->channel;
+       struct s2255_dev *dev = fh->dev;
        mutex_lock(&dev->lock);
-       dev->resources[fh->channel] = 0;
-       fh->resources[fh->channel] = 0;
+       channel->resources = 0;
+       fh->resources = 0;
        mutex_unlock(&dev->lock);
        dprintk(1, "res: put\n");
 }
@@ -869,12 +875,13 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                            struct v4l2_format *f)
 {
        struct s2255_fh *fh = priv;
+       struct s2255_channel *channel = fh->channel;
 
-       f->fmt.pix.width = fh->width;
-       f->fmt.pix.height = fh->height;
+       f->fmt.pix.width = channel->width;
+       f->fmt.pix.height = channel->height;
        f->fmt.pix.field = fh->vb_vidq.field;
-       f->fmt.pix.pixelformat = fh->fmt->fourcc;
-       f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3);
+       f->fmt.pix.pixelformat = channel->fmt->fourcc;
+       f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
        return 0;
 }
@@ -886,11 +893,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        enum v4l2_field field;
        int  b_any_field = 0;
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
+       struct s2255_channel *channel = fh->channel;
        int is_ntsc;
-
        is_ntsc =
-           (dev->vdev[fh->channel].current_norm & V4L2_STD_NTSC) ? 1 : 0;
+               (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
 
        fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
@@ -982,8 +988,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                            struct v4l2_format *f)
 {
        struct s2255_fh *fh = priv;
+       struct s2255_channel *channel = fh->channel;
        const struct s2255_fmt *fmt;
        struct videobuf_queue *q = &fh->vb_vidq;
+       struct s2255_mode mode;
        int ret;
        int norm;
 
@@ -1005,54 +1013,61 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out_s_fmt;
        }
 
-       if (res_locked(fh->dev, fh)) {
+       if (res_locked(fh)) {
                dprintk(1, "%s: channel busy\n", __func__);
                ret = -EBUSY;
                goto out_s_fmt;
        }
-
-       fh->fmt = fmt;
-       fh->width = f->fmt.pix.width;
-       fh->height = f->fmt.pix.height;
+       mode = channel->mode;
+       channel->fmt = fmt;
+       channel->width = f->fmt.pix.width;
+       channel->height = f->fmt.pix.height;
        fh->vb_vidq.field = f->fmt.pix.field;
        fh->type = f->type;
-       norm = norm_minw(&fh->dev->vdev[fh->channel]);
-       if (fh->width > norm_minw(&fh->dev->vdev[fh->channel])) {
-               if (fh->height > norm_minh(&fh->dev->vdev[fh->channel])) {
-                       if (fh->dev->cap_parm[fh->channel].capturemode &
+       norm = norm_minw(&channel->vdev);
+       if (channel->width > norm_minw(&channel->vdev)) {
+               if (channel->height > norm_minh(&channel->vdev)) {
+                       if (channel->cap_parm.capturemode &
                            V4L2_MODE_HIGHQUALITY)
-                               fh->mode.scale = SCALE_4CIFSI;
+                               mode.scale = SCALE_4CIFSI;
                        else
-                               fh->mode.scale = SCALE_4CIFS;
+                               mode.scale = SCALE_4CIFS;
                } else
-                       fh->mode.scale = SCALE_2CIFS;
+                       mode.scale = SCALE_2CIFS;
 
        } else {
-               fh->mode.scale = SCALE_1CIFS;
+               mode.scale = SCALE_1CIFS;
        }
-
        /* color mode */
-       switch (fh->fmt->fourcc) {
+       switch (channel->fmt->fourcc) {
        case V4L2_PIX_FMT_GREY:
-               fh->mode.color &= ~MASK_COLOR;
-               fh->mode.color |= COLOR_Y8;
+               mode.color &= ~MASK_COLOR;
+               mode.color |= COLOR_Y8;
                break;
        case V4L2_PIX_FMT_JPEG:
-               fh->mode.color &= ~MASK_COLOR;
-               fh->mode.color |= COLOR_JPG;
-               fh->mode.color |= (fh->dev->jc[fh->channel].quality << 8);
+               mode.color &= ~MASK_COLOR;
+               mode.color |= COLOR_JPG;
+               mode.color |= (channel->jc.quality << 8);
                break;
        case V4L2_PIX_FMT_YUV422P:
-               fh->mode.color &= ~MASK_COLOR;
-               fh->mode.color |= COLOR_YUVPL;
+               mode.color &= ~MASK_COLOR;
+               mode.color |= COLOR_YUVPL;
                break;
        case V4L2_PIX_FMT_YUYV:
        case V4L2_PIX_FMT_UYVY:
        default:
-               fh->mode.color &= ~MASK_COLOR;
-               fh->mode.color |= COLOR_YUVPK;
+               mode.color &= ~MASK_COLOR;
+               mode.color |= COLOR_YUVPK;
                break;
        }
+       if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+               mode.restart = 1;
+       else if (mode.scale != channel->mode.scale)
+               mode.restart = 1;
+       else if (mode.format != channel->mode.format)
+               mode.restart = 1;
+       channel->mode = mode;
+       (void) s2255_set_mode(channel, &mode);
        ret = 0;
 out_s_fmt:
        mutex_unlock(&q->vb_lock);
@@ -1197,26 +1212,27 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
  * When the restart parameter is set, we sleep for ONE frame to allow the
  * DSP time to get the new frame
  */
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+static int s2255_set_mode(struct s2255_channel *channel,
                          struct s2255_mode *mode)
 {
        int res;
        __le32 *buffer;
        unsigned long chn_rev;
+       struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
        mutex_lock(&dev->lock);
-       chn_rev = G_chnmap[chn];
-       dprintk(3, "%s channel %lu\n", __func__, chn);
+       chn_rev = G_chnmap[channel->idx];
+       dprintk(3, "%s channel: %d\n", __func__, channel->idx);
        /* if JPEG, set the quality */
        if ((mode->color & MASK_COLOR) == COLOR_JPG) {
                mode->color &= ~MASK_COLOR;
                mode->color |= COLOR_JPG;
                mode->color &= ~MASK_JPG_QUALITY;
-               mode->color |= (dev->jc[chn].quality << 8);
+               mode->color |= (channel->jc.quality << 8);
        }
        /* save the mode */
-       dev->mode[chn] = *mode;
-       dev->req_image_size[chn] = get_transfer_size(mode);
-       dprintk(1, "%s: reqsize %ld\n", __func__, dev->req_image_size[chn]);
+       channel->mode = *mode;
+       channel->req_image_size = get_transfer_size(mode);
+       dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
@@ -1227,38 +1243,38 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
        buffer[0] = IN_DATA_TOKEN;
        buffer[1] = (__le32) cpu_to_le32(chn_rev);
        buffer[2] = CMD_SET_MODE;
-       memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
-       dev->setmode_ready[chn] = 0;
+       memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
+       channel->setmode_ready = 0;
        res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
        if (debug)
                s2255_print_cfg(dev, mode);
        kfree(buffer);
        /* wait at least 3 frames before continuing */
        if (mode->restart) {
-               wait_event_timeout(dev->wait_setmode[chn],
-                                  (dev->setmode_ready[chn] != 0),
+               wait_event_timeout(channel->wait_setmode,
+                                  (channel->setmode_ready != 0),
                                   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
-               if (dev->setmode_ready[chn] != 1) {
+               if (channel->setmode_ready != 1) {
                        printk(KERN_DEBUG "s2255: no set mode response\n");
                        res = -EFAULT;
                }
        }
        /* clear the restart flag */
-       dev->mode[chn].restart = 0;
+       channel->mode.restart = 0;
        mutex_unlock(&dev->lock);
-       dprintk(1, "%s chn %lu, result: %d\n", __func__, chn, res);
+       dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
        return res;
 }
 
-static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
-                           u32 *pstatus)
+static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
 {
        int res;
        __le32 *buffer;
        u32 chn_rev;
+       struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
        mutex_lock(&dev->lock);
-       chn_rev = G_chnmap[chn];
-       dprintk(4, "%s chan %lu\n", __func__, chn);
+       chn_rev = G_chnmap[channel->idx];
+       dprintk(4, "%s chan %d\n", __func__, channel->idx);
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
@@ -1270,17 +1286,17 @@ static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
        buffer[1] = (__le32) cpu_to_le32(chn_rev);
        buffer[2] = CMD_STATUS;
        *pstatus = 0;
-       dev->vidstatus_ready[chn] = 0;
+       channel->vidstatus_ready = 0;
        res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
        kfree(buffer);
-       wait_event_timeout(dev->wait_vidstatus[chn],
-                          (dev->vidstatus_ready[chn] != 0),
+       wait_event_timeout(channel->wait_vidstatus,
+                          (channel->vidstatus_ready != 0),
                           msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
-       if (dev->vidstatus_ready[chn] != 1) {
+       if (channel->vidstatus_ready != 1) {
                printk(KERN_DEBUG "s2255: no vidstatus response\n");
                res = -EFAULT;
        }
-       *pstatus = dev->vidstatus[chn];
+       *pstatus = channel->vidstatus;
        dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
        mutex_unlock(&dev->lock);
        return res;
@@ -1291,9 +1307,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
        int res;
        struct s2255_fh *fh = priv;
        struct s2255_dev *dev = fh->dev;
-       struct s2255_mode *new_mode;
-       struct s2255_mode *old_mode;
-       int chn;
+       struct s2255_channel *channel = fh->channel;
        int j;
        dprintk(4, "%s\n", __func__);
        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1305,51 +1319,32 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
                return -EINVAL;
        }
 
-       if (!res_get(dev, fh)) {
+       if (!res_get(fh)) {
                s2255_dev_err(&dev->udev->dev, "stream busy\n");
                return -EBUSY;
        }
-
-       /* send a set mode command everytime with restart.
-          in case we switch resolutions or other parameters */
-       chn = fh->channel;
-       new_mode = &fh->mode;
-       old_mode = &fh->dev->mode[chn];
-
-       if ((new_mode->color & MASK_COLOR) != (old_mode->color & MASK_COLOR))
-               new_mode->restart = 1;
-       else if (new_mode->scale != old_mode->scale)
-               new_mode->restart = 1;
-       else if (new_mode->format != old_mode->format)
-               new_mode->restart = 1;
-
-       s2255_set_mode(dev, chn, new_mode);
-       new_mode->restart = 0;
-       *old_mode = *new_mode;
-       dev->cur_fmt[chn] = fh->fmt;
-       dev->last_frame[chn] = -1;
-       dev->bad_payload[chn] = 0;
-       dev->cur_frame[chn] = 0;
-       dev->frame_count[chn] = 0;
+       channel->last_frame = -1;
+       channel->bad_payload = 0;
+       channel->cur_frame = 0;
+       channel->frame_count = 0;
        for (j = 0; j < SYS_FRAMES; j++) {
-               dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
-               dev->buffer[chn].frame[j].cur_size = 0;
+               channel->buffer.frame[j].ulState = S2255_READ_IDLE;
+               channel->buffer.frame[j].cur_size = 0;
        }
        res = videobuf_streamon(&fh->vb_vidq);
        if (res == 0) {
-               s2255_start_acquire(dev, chn);
-               dev->b_acquire[chn] = 1;
-       } else {
-               res_free(dev, fh);
-       }
+               s2255_start_acquire(channel);
+               channel->b_acquire = 1;
+       } else
+               res_free(fh);
+
        return res;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
-       dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
+       dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
        if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                printk(KERN_ERR "invalid fh type0\n");
                return -EINVAL;
@@ -1358,16 +1353,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
                printk(KERN_ERR "invalid type i\n");
                return -EINVAL;
        }
-       s2255_stop_acquire(dev, fh->channel);
+       s2255_stop_acquire(fh->channel);
        videobuf_streamoff(&fh->vb_vidq);
-       res_free(dev, fh);
+       res_free(fh);
        return 0;
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_mode *mode;
+       struct s2255_mode mode;
        struct videobuf_queue *q = &fh->vb_vidq;
        int ret = 0;
        mutex_lock(&q->vb_lock);
@@ -1376,29 +1371,32 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
                ret = -EBUSY;
                goto out_s_std;
        }
-       if (res_locked(fh->dev, fh)) {
+       if (res_locked(fh)) {
                dprintk(1, "can't change standard after started\n");
                ret = -EBUSY;
                goto out_s_std;
        }
-       mode = &fh->mode;
+       mode = fh->channel->mode;
        if (*i & V4L2_STD_NTSC) {
                dprintk(4, "%s NTSC\n", __func__);
                /* if changing format, reset frame decimation/intervals */
-               if (mode->format != FORMAT_NTSC) {
-                       mode->format = FORMAT_NTSC;
-                       mode->fdec = FDEC_1;
+               if (mode.format != FORMAT_NTSC) {
+                       mode.restart = 1;
+                       mode.format = FORMAT_NTSC;
+                       mode.fdec = FDEC_1;
                }
        } else if (*i & V4L2_STD_PAL) {
                dprintk(4, "%s PAL\n", __func__);
-               mode->format = FORMAT_PAL;
-               if (mode->format != FORMAT_PAL) {
-                       mode->format = FORMAT_PAL;
-                       mode->fdec = FDEC_1;
+               if (mode.format != FORMAT_PAL) {
+                       mode.restart = 1;
+                       mode.format = FORMAT_PAL;
+                       mode.fdec = FDEC_1;
                }
        } else {
                ret = -EINVAL;
        }
+       if (mode.restart)
+               s2255_set_mode(fh->channel, &mode);
 out_s_std:
        mutex_unlock(&q->vb_lock);
        return ret;
@@ -1416,6 +1414,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
 {
        struct s2255_fh *fh = priv;
        struct s2255_dev *dev = fh->dev;
+       struct s2255_channel *channel = fh->channel;
        u32 status = 0;
        if (inp->index != 0)
                return -EINVAL;
@@ -1424,7 +1423,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
        inp->status = 0;
        if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
                int rc;
-               rc = s2255_cmd_status(dev, fh->channel, &status);
+               rc = s2255_cmd_status(fh->channel, &status);
                dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
                if (rc == 0)
                        inp->status =  (status & 0x01) ? 0
@@ -1436,7 +1435,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
                strlcpy(inp->name, "Composite", sizeof(inp->name));
                break;
        case 0x2257:
-               strlcpy(inp->name, (fh->channel < 2) ? "Composite" : "S-Video",
+               strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
                        sizeof(inp->name));
                break;
        }
@@ -1460,6 +1459,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
                            struct v4l2_queryctrl *qc)
 {
        struct s2255_fh *fh = priv;
+       struct s2255_channel *channel = fh->channel;
        struct s2255_dev *dev = fh->dev;
        switch (qc->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -1477,7 +1477,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
        case V4L2_CID_PRIVATE_COLORFILTER:
                if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
                        return -EINVAL;
-               if ((dev->pid == 0x2257) && (fh->channel > 1))
+               if ((dev->pid == 0x2257) && (channel->idx > 1))
                        return -EINVAL;
                strlcpy(qc->name, "Color Filter", sizeof(qc->name));
                qc->type = V4L2_CTRL_TYPE_MENU;
@@ -1499,25 +1499,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct s2255_fh *fh = priv;
        struct s2255_dev *dev = fh->dev;
+       struct s2255_channel *channel = fh->channel;
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               ctrl->value = fh->mode.bright;
+               ctrl->value = channel->mode.bright;
                break;
        case V4L2_CID_CONTRAST:
-               ctrl->value = fh->mode.contrast;
+               ctrl->value = channel->mode.contrast;
                break;
        case V4L2_CID_SATURATION:
-               ctrl->value = fh->mode.saturation;
+               ctrl->value = channel->mode.saturation;
                break;
        case V4L2_CID_HUE:
-               ctrl->value = fh->mode.hue;
+               ctrl->value = channel->mode.hue;
                break;
        case V4L2_CID_PRIVATE_COLORFILTER:
                if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
                        return -EINVAL;
-               if ((dev->pid == 0x2257) && (fh->channel > 1))
+               if ((dev->pid == 0x2257) && (channel->idx > 1))
                        return -EINVAL;
-               ctrl->value = !((fh->mode.color & MASK_INPUT_TYPE) >> 16);
+               ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
                break;
        default:
                return -EINVAL;
@@ -1530,41 +1531,42 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
-       struct s2255_mode *mode;
-       mode = &fh->mode;
+       struct s2255_channel *channel = fh->channel;
+       struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+       struct s2255_mode mode;
+       mode = channel->mode;
        dprintk(4, "%s\n", __func__);
        /* update the mode to the corresponding value */
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               mode->bright = ctrl->value;
+               mode.bright = ctrl->value;
                break;
        case V4L2_CID_CONTRAST:
-               mode->contrast = ctrl->value;
+               mode.contrast = ctrl->value;
                break;
        case V4L2_CID_HUE:
-               mode->hue = ctrl->value;
+               mode.hue = ctrl->value;
                break;
        case V4L2_CID_SATURATION:
-               mode->saturation = ctrl->value;
+               mode.saturation = ctrl->value;
                break;
        case V4L2_CID_PRIVATE_COLORFILTER:
                if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
                        return -EINVAL;
-               if ((dev->pid == 0x2257) && (fh->channel > 1))
+               if ((dev->pid == 0x2257) && (channel->idx > 1))
                        return -EINVAL;
-               mode->color &= ~MASK_INPUT_TYPE;
-               mode->color |= ((ctrl->value ? 0 : 1) << 16);
+               mode.color &= ~MASK_INPUT_TYPE;
+               mode.color |= ((ctrl->value ? 0 : 1) << 16);
                break;
        default:
                return -EINVAL;
        }
-       mode->restart = 0;
+       mode.restart = 0;
        /* set mode here.  Note: stream does not need restarted.
           some V4L programs restart stream unnecessarily
           after a s_crtl.
        */
-       s2255_set_mode(dev, fh->channel, mode);
+       s2255_set_mode(fh->channel, &mode);
        return 0;
 }
 
@@ -1572,8 +1574,8 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,
                         struct v4l2_jpegcompression *jc)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
-       *jc = dev->jc[fh->channel];
+       struct s2255_channel *channel = fh->channel;
+       *jc = channel->jc;
        dprintk(2, "%s: quality %d\n", __func__, jc->quality);
        return 0;
 }
@@ -1582,10 +1584,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
                         struct v4l2_jpegcompression *jc)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
+       struct s2255_channel *channel = fh->channel;
        if (jc->quality < 0 || jc->quality > 100)
                return -EINVAL;
-       dev->jc[fh->channel].quality = jc->quality;
+       channel->jc.quality = jc->quality;
        dprintk(2, "%s: quality %d\n", __func__, jc->quality);
        return 0;
 }
@@ -1594,17 +1596,17 @@ static int vidioc_g_parm(struct file *file, void *priv,
                         struct v4l2_streamparm *sp)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
        __u32 def_num, def_dem;
+       struct s2255_channel *channel = fh->channel;
        if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
        memset(sp, 0, sizeof(struct v4l2_streamparm));
        sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
-       def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
-       def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+       sp->parm.capture.capturemode = channel->cap_parm.capturemode;
+       def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+       def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
        sp->parm.capture.timeperframe.denominator = def_dem;
-       switch (fh->mode.fdec) {
+       switch (channel->mode.fdec) {
        default:
        case FDEC_1:
                sp->parm.capture.timeperframe.numerator = def_num;
@@ -1630,17 +1632,19 @@ static int vidioc_s_parm(struct file *file, void *priv,
                         struct v4l2_streamparm *sp)
 {
        struct s2255_fh *fh = priv;
-       struct s2255_dev *dev = fh->dev;
+       struct s2255_channel *channel = fh->channel;
+       struct s2255_mode mode;
        int fdec = FDEC_1;
        __u32 def_num, def_dem;
        if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
+       mode = channel->mode;
        /* high quality capture mode requires a stream restart */
-       if (dev->cap_parm[fh->channel].capturemode
-           != sp->parm.capture.capturemode && res_locked(fh->dev, fh))
+       if (channel->cap_parm.capturemode
+           != sp->parm.capture.capturemode && res_locked(fh))
                return -EBUSY;
-       def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
-       def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+       def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
+       def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
        if (def_dem != sp->parm.capture.timeperframe.denominator)
                sp->parm.capture.timeperframe.numerator = def_num;
        else if (sp->parm.capture.timeperframe.numerator <= def_num)
@@ -1655,9 +1659,9 @@ static int vidioc_s_parm(struct file *file, void *priv,
                sp->parm.capture.timeperframe.numerator = def_num * 5;
                fdec = FDEC_5;
        }
-       fh->mode.fdec = fdec;
+       mode.fdec = fdec;
        sp->parm.capture.timeperframe.denominator = def_dem;
-       s2255_set_mode(dev, fh->channel, &fh->mode);
+       s2255_set_mode(channel, &mode);
        dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
                __func__,
                sp->parm.capture.capturemode,
@@ -1707,24 +1711,13 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
 static int s2255_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
-       struct s2255_dev *dev = video_drvdata(file);
+       struct s2255_channel *channel = video_drvdata(file);
+       struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
        struct s2255_fh *fh;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       int i = 0;
-       int cur_channel = -1;
        int state;
        dprintk(1, "s2255: open called (dev=%s)\n",
                video_device_node_name(vdev));
-
-       for (i = 0; i < MAX_CHANNELS; i++) {
-               if (&dev->vdev[i] == vdev) {
-                       cur_channel = i;
-                       break;
-               }
-       }
-       if (i == MAX_CHANNELS)
-               return -ENODEV;
-
        /*
         * open lock necessary to prevent multiple instances
         * of v4l-conf (or other programs) from simultaneously
@@ -1806,24 +1799,20 @@ static int s2255_open(struct file *file)
        file->private_data = fh;
        fh->dev = dev;
        fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       fh->mode = dev->mode[cur_channel];
-       fh->fmt = dev->cur_fmt[cur_channel];
-       /* default 4CIF NTSC */
-       fh->width = LINE_SZ_4CIFS_NTSC;
-       fh->height = NUM_LINES_4CIFS_NTSC * 2;
-       fh->channel = cur_channel;
-       /* configure channel to default state */
-       if (!dev->chn_configured[cur_channel]) {
-               s2255_set_mode(dev, cur_channel, &fh->mode);
-               dev->chn_configured[cur_channel] = 1;
+       fh->channel = channel;
+       if (!channel->configured) {
+               /* configure channel to default state */
+               channel->fmt = &formats[0];
+               s2255_set_mode(channel, &channel->mode);
+               channel->configured = 1;
        }
        dprintk(1, "%s: dev=%s type=%s\n", __func__,
                video_device_node_name(vdev), v4l2_type_names[type]);
        dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
                (unsigned long)fh, (unsigned long)dev,
-               (unsigned long)&dev->vidq[cur_channel]);
+               (unsigned long)&channel->vidq);
        dprintk(4, "%s: list_empty active=%d\n", __func__,
-               list_empty(&dev->vidq[cur_channel].active));
+               list_empty(&channel->vidq.active));
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
                                    NULL, &dev->slock,
                                    fh->type,
@@ -1865,6 +1854,7 @@ static void s2255_destroy(struct s2255_dev *dev)
        mutex_destroy(&dev->open_lock);
        mutex_destroy(&dev->lock);
        usb_put_dev(dev->udev);
+       v4l2_device_unregister(&dev->v4l2_dev);
        dprintk(1, "%s", __func__);
        kfree(dev);
 }
@@ -1874,14 +1864,15 @@ static int s2255_release(struct file *file)
        struct s2255_fh *fh = file->private_data;
        struct s2255_dev *dev = fh->dev;
        struct video_device *vdev = video_devdata(file);
+       struct s2255_channel *channel = fh->channel;
        if (!dev)
                return -ENODEV;
        /* turn off stream */
        if (res_check(fh)) {
-               if (dev->b_acquire[fh->channel])
-                       s2255_stop_acquire(dev, fh->channel);
+               if (channel->b_acquire)
+                       s2255_stop_acquire(fh->channel);
                videobuf_streamoff(&fh->vb_vidq);
-               res_free(dev, fh);
+               res_free(fh);
        }
        videobuf_mmap_free(&fh->vb_vidq);
        dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
@@ -1945,9 +1936,10 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
 
 static void s2255_video_device_release(struct video_device *vdev)
 {
-       struct s2255_dev *dev = video_get_drvdata(vdev);
-       dprintk(4, "%s, chnls: %d \n", __func__, atomic_read(&dev->channels));
-       if (atomic_dec_and_test(&dev->channels))
+       struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
+       dprintk(4, "%s, chnls: %d \n", __func__,
+               atomic_read(&dev->num_channels));
+       if (atomic_dec_and_test(&dev->num_channels))
                s2255_destroy(dev);
        return;
 }
@@ -1966,47 +1958,48 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
        int ret;
        int i;
        int cur_nr = video_nr;
+       struct s2255_channel *channel;
        ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
        if (ret)
                return ret;
        /* initialize all video 4 linux */
        /* register 4 video devices */
        for (i = 0; i < MAX_CHANNELS; i++) {
-               INIT_LIST_HEAD(&dev->vidq[i].active);
-               dev->vidq[i].dev = dev;
-               dev->vidq[i].channel = i;
+               channel = &dev->channel[i];
+               INIT_LIST_HEAD(&channel->vidq.active);
+               channel->vidq.dev = dev;
                /* register 4 video devices */
-               memcpy(&dev->vdev[i], &template, sizeof(struct video_device));
-               dev->vdev[i].v4l2_dev = &dev->v4l2_dev;
-               video_set_drvdata(&dev->vdev[i], dev);
+               channel->vdev = template;
+               channel->vdev.v4l2_dev = &dev->v4l2_dev;
+               video_set_drvdata(&channel->vdev, channel);
                if (video_nr == -1)
-                       ret = video_register_device(&dev->vdev[i],
+                       ret = video_register_device(&channel->vdev,
                                                    VFL_TYPE_GRABBER,
                                                    video_nr);
                else
-                       ret = video_register_device(&dev->vdev[i],
+                       ret = video_register_device(&channel->vdev,
                                                    VFL_TYPE_GRABBER,
                                                    cur_nr + i);
+
                if (ret) {
                        dev_err(&dev->udev->dev,
                                "failed to register video device!\n");
                        break;
                }
-               atomic_inc(&dev->channels);
+               atomic_inc(&dev->num_channels);
                v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
-                         video_device_node_name(&dev->vdev[i]));
+                         video_device_node_name(&channel->vdev));
 
        }
-
        printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
               S2255_MAJOR_VERSION,
               S2255_MINOR_VERSION);
        /* if no channels registered, return error and probe will fail*/
-       if (atomic_read(&dev->channels) == 0) {
+       if (atomic_read(&dev->num_channels) == 0) {
                v4l2_device_unregister(&dev->v4l2_dev);
                return ret;
        }
-       if (atomic_read(&dev->channels) != MAX_CHANNELS)
+       if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
                printk(KERN_WARNING "s2255: Not all channels available.\n");
        return 0;
 }
@@ -2033,12 +2026,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
        s32 idx = -1;
        struct s2255_framei *frm;
        unsigned char *pdata;
-
+       struct s2255_channel *channel;
        dprintk(100, "buffer to user\n");
-
-       idx = dev->cur_frame[dev->cc];
-       frm = &dev->buffer[dev->cc].frame[idx];
-
+       channel = &dev->channel[dev->cc];
+       idx = channel->cur_frame;
+       frm = &channel->buffer.frame[idx];
        if (frm->ulState == S2255_READ_IDLE) {
                int jj;
                unsigned int cc;
@@ -2063,16 +2055,18 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                }
                                /* reverse it */
                                dev->cc = G_chnmap[cc];
+                               channel = &dev->channel[dev->cc];
                                payload =  pdword[3];
-                               if (payload > dev->req_image_size[dev->cc]) {
-                                       dev->bad_payload[dev->cc]++;
+                               if (payload > channel->req_image_size) {
+                                       channel->bad_payload++;
                                        /* discard the bad frame */
                                        return -EINVAL;
                                }
-                               dev->pkt_size[dev->cc] = payload;
-                               dev->jpg_size[dev->cc] = pdword[4];
+                               channel->pkt_size = payload;
+                               channel->jpg_size = pdword[4];
                                break;
                        case S2255_MARKER_RESPONSE:
+
                                pdata += DEF_USB_BLOCK;
                                jj += DEF_USB_BLOCK;
                                if (pdword[1] >= MAX_CHANNELS)
@@ -2080,12 +2074,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                cc = G_chnmap[pdword[1]];
                                if (cc >= MAX_CHANNELS)
                                        break;
+                               channel = &dev->channel[cc];
                                switch (pdword[2]) {
                                case S2255_RESPONSE_SETMODE:
                                        /* check if channel valid */
                                        /* set mode ready */
-                                       dev->setmode_ready[cc] = 1;
-                                       wake_up(&dev->wait_setmode[cc]);
+                                       channel->setmode_ready = 1;
+                                       wake_up(&channel->wait_setmode);
                                        dprintk(5, "setmode ready %d\n", cc);
                                        break;
                                case S2255_RESPONSE_FW:
@@ -2099,9 +2094,9 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                        wake_up(&dev->fw_data->wait_fw);
                                        break;
                                case S2255_RESPONSE_STATUS:
-                                       dev->vidstatus[cc] = pdword[3];
-                                       dev->vidstatus_ready[cc] = 1;
-                                       wake_up(&dev->wait_vidstatus[cc]);
+                                       channel->vidstatus = pdword[3];
+                                       channel->vidstatus_ready = 1;
+                                       wake_up(&channel->wait_vidstatus);
                                        dprintk(5, "got vidstatus %x chan %d\n",
                                                pdword[3], cc);
                                        break;
@@ -2118,13 +2113,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                if (!bframe)
                        return -EINVAL;
        }
-
-
-       idx = dev->cur_frame[dev->cc];
-       frm = &dev->buffer[dev->cc].frame[idx];
-
+       channel = &dev->channel[dev->cc];
+       idx = channel->cur_frame;
+       frm = &channel->buffer.frame[idx];
        /* search done.  now find out if should be acquiring on this channel */
-       if (!dev->b_acquire[dev->cc]) {
+       if (!channel->b_acquire) {
                /* we found a frame, but this channel is turned off */
                frm->ulState = S2255_READ_IDLE;
                return -EINVAL;
@@ -2149,30 +2142,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 
        copy_size = (pipe_info->cur_transfer_size - offset);
 
-       size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
+       size = channel->pkt_size - PREFIX_SIZE;
 
        /* sanity check on pdest */
-       if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+       if ((copy_size + frm->cur_size) < channel->req_image_size)
                memcpy(pdest, psrc, copy_size);
 
        frm->cur_size += copy_size;
        dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
 
        if (frm->cur_size >= size) {
-
-               u32 cc = dev->cc;
                dprintk(2, "****************[%d]Buffer[%d]full*************\n",
-                       cc, idx);
-               dev->last_frame[cc] = dev->cur_frame[cc];
-               dev->cur_frame[cc]++;
+                       dev->cc, idx);
+               channel->last_frame = channel->cur_frame;
+               channel->cur_frame++;
                /* end of system frame ring buffer, start at zero */
-               if ((dev->cur_frame[cc] == SYS_FRAMES) ||
-                   (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
-                       dev->cur_frame[cc] = 0;
+               if ((channel->cur_frame == SYS_FRAMES) ||
+                   (channel->cur_frame == channel->buffer.dwFrames))
+                       channel->cur_frame = 0;
                /* frame ready */
-               if (dev->b_acquire[cc])
-                       s2255_got_frame(dev, cc, dev->jpg_size[cc]);
-               dev->frame_count[cc]++;
+               if (channel->b_acquire)
+                       s2255_got_frame(channel, channel->jpg_size);
+               channel->frame_count++;
                frm->ulState = S2255_READ_IDLE;
                frm->cur_size = 0;
 
@@ -2245,16 +2236,12 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
  * Create the system ring buffer to copy frames into from the
  * usb read pipe.
  */
-static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
+static int s2255_create_sys_buffers(struct s2255_channel *channel)
 {
        unsigned long i;
        unsigned long reqsize;
        dprintk(1, "create sys buffers\n");
-       if (chn >= MAX_CHANNELS)
-               return -1;
-
-       dev->buffer[chn].dwFrames = SYS_FRAMES;
-
+       channel->buffer.dwFrames = SYS_FRAMES;
        /* always allocate maximum size(PAL) for system buffers */
        reqsize = SYS_FRAMES_MAXSIZE;
 
@@ -2263,42 +2250,40 @@ static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
 
        for (i = 0; i < SYS_FRAMES; i++) {
                /* allocate the frames */
-               dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize);
-
-               dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n",
-                       &dev->buffer[chn].frame[i], chn, i,
-                       dev->buffer[chn].frame[i].lpvbits);
-               dev->buffer[chn].frame[i].size = reqsize;
-               if (dev->buffer[chn].frame[i].lpvbits == NULL) {
+               channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
+               dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
+                       &channel->buffer.frame[i], channel->idx, i,
+                       channel->buffer.frame[i].lpvbits);
+               channel->buffer.frame[i].size = reqsize;
+               if (channel->buffer.frame[i].lpvbits == NULL) {
                        printk(KERN_INFO "out of memory.  using less frames\n");
-                       dev->buffer[chn].dwFrames = i;
+                       channel->buffer.dwFrames = i;
                        break;
                }
        }
 
        /* make sure internal states are set */
        for (i = 0; i < SYS_FRAMES; i++) {
-               dev->buffer[chn].frame[i].ulState = 0;
-               dev->buffer[chn].frame[i].cur_size = 0;
+               channel->buffer.frame[i].ulState = 0;
+               channel->buffer.frame[i].cur_size = 0;
        }
 
-       dev->cur_frame[chn] = 0;
-       dev->last_frame[chn] = -1;
+       channel->cur_frame = 0;
+       channel->last_frame = -1;
        return 0;
 }
 
-static int s2255_release_sys_buffers(struct s2255_dev *dev,
-                                    unsigned long channel)
+static int s2255_release_sys_buffers(struct s2255_channel *channel)
 {
        unsigned long i;
        dprintk(1, "release sys buffers\n");
        for (i = 0; i < SYS_FRAMES; i++) {
-               if (dev->buffer[channel].frame[i].lpvbits) {
+               if (channel->buffer.frame[i].lpvbits) {
                        dprintk(1, "vfree %p\n",
-                               dev->buffer[channel].frame[i].lpvbits);
-                       vfree(dev->buffer[channel].frame[i].lpvbits);
+                               channel->buffer.frame[i].lpvbits);
+                       vfree(channel->buffer.frame[i].lpvbits);
                }
-               dev->buffer[channel].frame[i].lpvbits = NULL;
+               channel->buffer.frame[i].lpvbits = NULL;
        }
        return 0;
 }
@@ -2335,17 +2320,20 @@ static int s2255_board_init(struct s2255_dev *dev)
                        fw_ver & 0xff);
 
        for (j = 0; j < MAX_CHANNELS; j++) {
-               dev->b_acquire[j] = 0;
-               dev->mode[j] = mode_def;
+               struct s2255_channel *channel = &dev->channel[j];
+               channel->b_acquire = 0;
+               channel->mode = mode_def;
                if (dev->pid == 0x2257 && j > 1)
-                       dev->mode[j].color |= (1 << 16);
-               dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
-               dev->cur_fmt[j] = &formats[0];
-               dev->mode[j].restart = 1;
-               dev->req_image_size[j] = get_transfer_size(&mode_def);
-               dev->frame_count[j] = 0;
+                       channel->mode.color |= (1 << 16);
+               channel->jc.quality = S2255_DEF_JPEG_QUAL;
+               channel->width = LINE_SZ_4CIFS_NTSC;
+               channel->height = NUM_LINES_4CIFS_NTSC * 2;
+               channel->fmt = &formats[0];
+               channel->mode.restart = 1;
+               channel->req_image_size = get_transfer_size(&mode_def);
+               channel->frame_count = 0;
                /* create the system buffers */
-               s2255_create_sys_buffers(dev, j);
+               s2255_create_sys_buffers(channel);
        }
        /* start read pipe */
        s2255_start_readpipe(dev);
@@ -2359,14 +2347,12 @@ static int s2255_board_shutdown(struct s2255_dev *dev)
        dprintk(1, "%s: dev: %p", __func__,  dev);
 
        for (i = 0; i < MAX_CHANNELS; i++) {
-               if (dev->b_acquire[i])
-                       s2255_stop_acquire(dev, i);
+               if (dev->channel[i].b_acquire)
+                       s2255_stop_acquire(&dev->channel[i]);
        }
-
        s2255_stop_readpipe(dev);
-
        for (i = 0; i < MAX_CHANNELS; i++)
-               s2255_release_sys_buffers(dev, i);
+               s2255_release_sys_buffers(&dev->channel[i]);
        /* release transfer buffer */
        kfree(dev->pipe.transfer_buffer);
        return 0;
@@ -2459,29 +2445,26 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
 }
 
 /* starts acquisition process */
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_start_acquire(struct s2255_channel *channel)
 {
        unsigned char *buffer;
        int res;
        unsigned long chn_rev;
        int j;
-       if (chn >= MAX_CHANNELS) {
-               dprintk(2, "start acquire failed, bad channel %lu\n", chn);
-               return -1;
-       }
-       chn_rev = G_chnmap[chn];
+       struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+       chn_rev = G_chnmap[channel->idx];
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
                return -ENOMEM;
        }
 
-       dev->last_frame[chn] = -1;
-       dev->bad_payload[chn] = 0;
-       dev->cur_frame[chn] = 0;
+       channel->last_frame = -1;
+       channel->bad_payload = 0;
+       channel->cur_frame = 0;
        for (j = 0; j < SYS_FRAMES; j++) {
-               dev->buffer[chn].frame[j].ulState = 0;
-               dev->buffer[chn].frame[j].cur_size = 0;
+               channel->buffer.frame[j].ulState = 0;
+               channel->buffer.frame[j].cur_size = 0;
        }
 
        /* send the start command */
@@ -2492,21 +2475,18 @@ static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
        if (res != 0)
                dev_err(&dev->udev->dev, "CMD_START error\n");
 
-       dprintk(2, "start acquire exit[%lu] %d \n", chn, res);
+       dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
        kfree(buffer);
        return 0;
 }
 
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_stop_acquire(struct s2255_channel *channel)
 {
        unsigned char *buffer;
        int res;
        unsigned long chn_rev;
-       if (chn >= MAX_CHANNELS) {
-               dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
-               return -1;
-       }
-       chn_rev = G_chnmap[chn];
+       struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+       chn_rev = G_chnmap[channel->idx];
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
@@ -2520,8 +2500,8 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
        if (res != 0)
                dev_err(&dev->udev->dev, "CMD_STOP error\n");
        kfree(buffer);
-       dev->b_acquire[chn] = 0;
-       dprintk(4, "%s: chn %lu, res %d\n", __func__, chn, res);
+       channel->b_acquire = 0;
+       dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
        return res;
 }
 
@@ -2575,7 +2555,7 @@ static int s2255_probe(struct usb_interface *interface,
                s2255_dev_err(&interface->dev, "out of memory\n");
                return -ENOMEM;
        }
-       atomic_set(&dev->channels, 0);
+       atomic_set(&dev->num_channels, 0);
        dev->pid = id->idProduct;
        dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
        if (!dev->fw_data)
@@ -2612,8 +2592,10 @@ static int s2255_probe(struct usb_interface *interface,
        dev->timer.data = (unsigned long)dev->fw_data;
        init_waitqueue_head(&dev->fw_data->wait_fw);
        for (i = 0; i < MAX_CHANNELS; i++) {
-               init_waitqueue_head(&dev->wait_setmode[i]);
-               init_waitqueue_head(&dev->wait_vidstatus[i]);
+               struct s2255_channel *channel = &dev->channel[i];
+               dev->channel[i].idx = i;
+               init_waitqueue_head(&channel->wait_setmode);
+               init_waitqueue_head(&channel->wait_vidstatus);
        }
 
        dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2651,7 +2633,7 @@ static int s2255_probe(struct usb_interface *interface,
                        printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
                if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
                        printk(KERN_WARNING "s2255: 2257 requires firmware %d"
-                              "or above.\n", S2255_MIN_DSP_COLORFILTER);
+                              " or above.\n", S2255_MIN_DSP_COLORFILTER);
        }
        usb_reset_device(dev->udev);
        /* load 2255 board specific */
@@ -2693,25 +2675,23 @@ static void s2255_disconnect(struct usb_interface *interface)
 {
        struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
        int i;
-       int channels = atomic_read(&dev->channels);
-       v4l2_device_unregister(&dev->v4l2_dev);
+       int channels = atomic_read(&dev->num_channels);
+       v4l2_device_disconnect(&dev->v4l2_dev);
        /*see comments in the uvc_driver.c usb disconnect function */
-       atomic_inc(&dev->channels);
+       atomic_inc(&dev->num_channels);
        /* unregister each video device. */
-       for (i = 0; i < channels; i++) {
-               if (video_is_registered(&dev->vdev[i]))
-                       video_unregister_device(&dev->vdev[i]);
-       }
+       for (i = 0; i < channels; i++)
+               video_unregister_device(&dev->channel[i].vdev);
        /* wake up any of our timers */
        atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
        wake_up(&dev->fw_data->wait_fw);
        for (i = 0; i < MAX_CHANNELS; i++) {
-               dev->setmode_ready[i] = 1;
-               wake_up(&dev->wait_setmode[i]);
-               dev->vidstatus_ready[i] = 1;
-               wake_up(&dev->wait_vidstatus[i]);
+               dev->channel[i].setmode_ready = 1;
+               wake_up(&dev->channel[i].wait_setmode);
+               dev->channel[i].vidstatus_ready = 1;
+               wake_up(&dev->channel[i].wait_vidstatus);
        }
-       if (atomic_dec_and_test(&dev->channels))
+       if (atomic_dec_and_test(&dev->num_channels))
                s2255_destroy(dev);
        dev_info(&interface->dev, "%s\n", __func__);
 }
index d3bd82ad010a18010458cb0357de05501a11ec3e..10460fd3ce3994c5865e11e4f990407b2b583c47 100644 (file)
@@ -630,7 +630,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
        /* release the old buffer */
        if (substream->runtime->dma_area) {
                saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-               videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+               videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                substream->runtime->dma_area = NULL;
        }
@@ -646,12 +646,12 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
                return err;
        }
 
-       if (0 != (err = videobuf_sg_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
+       if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
                dsp_buffer_free(dev);
                return err;
        }
        if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
-               videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+               videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                return err;
        }
@@ -660,7 +660,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
                                                dev->dmasound.dma.sglen,
                                                0))) {
                saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-               videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+               videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                return err;
        }
@@ -669,7 +669,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
           byte, but it doesn't work. So I allocate the DMA using the
           V4L functions, and force ALSA to use that as the DMA area */
 
-       substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+       substream->runtime->dma_area = dev->dmasound.dma.vaddr;
        substream->runtime->dma_bytes = dev->dmasound.bufsize;
        substream->runtime->dma_addr = 0;
 
@@ -696,7 +696,7 @@ static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
 
        if (substream->runtime->dma_area) {
                saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-               videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+               videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                substream->runtime->dma_area = NULL;
        }
@@ -1080,7 +1080,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
        /* Card "creation" */
 
        card->private_free = snd_saa7134_free;
-       chip = (snd_card_saa7134_t *) card->private_data;
+       chip = card->private_data;
 
        spin_lock_init(&chip->lock);
        spin_lock_init(&chip->mixer_lock);
index 07f6bb8ef9d949b36e52530d17a8350cf86648b9..ec697fcd406ede6b23c9691ceb5d0fe1fc0134a4 100644 (file)
@@ -5462,6 +5462,30 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = TV,
                },
        },
+       [SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = {
+               .name           = "TechoTrend TT-budget T-3000",
+               .tuner_type     = TUNER_PHILIPS_TD1316,
+               .audio_clock    = 0x00187de7,
+               .radio_type     = UNSET,
+               .tuner_addr     = 0x63,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 3,
+                       .amux   = TV,
+                       .tv     = 1,
+               }, {
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE2,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2,
+               } },
+       },
 
 };
 
@@ -6630,6 +6654,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x107d,
                .subdevice    = 0x6655,
                .driver_data  = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x13c2,
+               .subdevice    = 0x2804,
+               .driver_data  = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -7320,6 +7350,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
        case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+       case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
        {
 
                /* The Philips EUROPA based hybrid boards have the tuner
index 90f23188129718b90f201410181cb278cd6ef5fb..40bc635e8a3f45f82608c3fbfd9be92042e76819 100644 (file)
@@ -256,7 +256,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
        BUG_ON(in_interrupt());
 
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_unmap(q, dma);
+       videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
index 31e82be1b7e721e66bcc43f731fd772239219436..f26fe7661a1df31a1ee0a7a6b67de864d5c111ad 100644 (file)
@@ -481,6 +481,17 @@ static struct tda1004x_config medion_cardbus = {
        .request_firmware = philips_tda1004x_request_firmware
 };
 
+static struct tda1004x_config technotrend_budget_t3000_config = {
+       .demod_address = 0x8,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_4M,
+       .agc_config    = TDA10046_AGC_DEFAULT,
+       .if_freq       = TDA10046_FREQ_3617,
+       .tuner_address = 0x63,
+       .request_firmware = philips_tda1004x_request_firmware
+};
+
 /* ------------------------------------------------------------------
  * tda 1004x based cards with philips silicon tuner
  */
@@ -1168,6 +1179,18 @@ static int dvb_init(struct saa7134_dev *dev)
                        fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
                }
                break;
+       case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+               fe0->dvb.frontend = dvb_attach(tda10046_attach,
+                                              &technotrend_budget_t3000_config,
+                                              &dev->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+                       fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+                       fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+                       fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+                       fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+               }
+               break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
                fe0->dvb.frontend = dvb_attach(tda10046_attach,
                                               &philips_tu1216_61_config,
index 756a1ca8833d89a50153a910064d8ec8e0272fd9..c040a180854228628ea3374a1ec322ec539b447e 100644 (file)
@@ -304,6 +304,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_BEHOLD_H7             178
 #define SAA7134_BOARD_BEHOLD_A7             179
 #define SAA7134_BOARD_AVERMEDIA_M733A       180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
index 961bfa2fea97eb9f65a5900d36fcc0d181e2ffa2..2b24bd0de3ad47257752ea69a1e3619d229de108 100644 (file)
@@ -633,6 +633,12 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
                cdwdr_width *= 2;
        }
 
+       /* CSI2 special configuration */
+       if (pcdev->pdata->csi2_dev) {
+               in_width = ((in_width - 2) * 2);
+               left_offset *= 2;
+       }
+
        /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
        camor = left_offset | (top_offset << 16);
 
@@ -743,16 +749,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
                switch (cam->code) {
-               case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+               case V4L2_MBUS_FMT_UYVY8_2X8:
                        value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
                        break;
-               case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+               case V4L2_MBUS_FMT_VYUY8_2X8:
                        value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
                        break;
-               case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+               case V4L2_MBUS_FMT_YUYV8_2X8:
                        value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
                        break;
-               case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+               case V4L2_MBUS_FMT_YVYU8_2X8:
                        value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
                        break;
                default:
@@ -767,6 +773,11 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
        value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
        value |= pcdev->is_16bit ? 1 << 12 : 0;
+
+       /* CSI2 mode */
+       if (pcdev->pdata->csi2_dev)
+               value |= 3 << 12;
+
        ceu_write(pcdev, CAMCR, value);
 
        ceu_write(pcdev, CAPCR, 0x00300000);
@@ -883,6 +894,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct device *dev = icd->dev.parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int ret, k, n;
        int formats = 0;
        struct sh_mobile_ceu_cam *cam;
@@ -896,19 +909,19 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
 
        fmt = soc_mbus_get_fmtdesc(code);
        if (!fmt) {
-               dev_err(icd->dev.parent,
-                       "Invalid format code #%u: %d\n", idx, code);
+               dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
                return -EINVAL;
        }
 
-       ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
-       if (ret < 0)
-               return 0;
+       if (!pcdev->pdata->csi2_dev) {
+               ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
+               if (ret < 0)
+                       return 0;
+       }
 
        if (!icd->host_priv) {
                struct v4l2_mbus_framefmt mf;
                struct v4l2_rect rect;
-               struct device *dev = icd->dev.parent;
                int shift = 0;
 
                /* FIXME: subwindow is lost between close / open */
@@ -927,7 +940,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                        /* Try 2560x1920, 1280x960, 640x480, 320x240 */
                        mf.width        = 2560 >> shift;
                        mf.height       = 1920 >> shift;
-                       ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+                       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+                                                        s_mbus_fmt, &mf);
                        if (ret < 0)
                                return ret;
                        shift++;
@@ -965,10 +979,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                cam->extra_fmt = NULL;
 
        switch (code) {
-       case V4L2_MBUS_FMT_YUYV8_2X8_BE:
-       case V4L2_MBUS_FMT_YVYU8_2X8_BE:
-       case V4L2_MBUS_FMT_YUYV8_2X8_LE:
-       case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
                if (cam->extra_fmt)
                        break;
 
@@ -1005,7 +1019,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                xlate->code     = code;
                xlate++;
                dev_dbg(dev, "Providing format %s in pass-through mode\n",
-                       xlate->host_fmt->name);
+                       fmt->name);
        }
 
        return formats;
@@ -1228,7 +1242,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
        struct v4l2_cropcap cap;
        int ret;
 
-       ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+                                        s_mbus_fmt, mf);
        if (ret < 0)
                return ret;
 
@@ -1257,7 +1272,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
                tmp_h = min(2 * tmp_h, max_height);
                mf->width = tmp_w;
                mf->height = tmp_h;
-               ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+               ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+                                                s_mbus_fmt, mf);
                dev_geo(dev, "Camera scaled to %ux%u\n",
                        mf->width, mf->height);
                if (ret < 0) {
@@ -1514,7 +1530,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        struct device *dev = icd->dev.parent;
        __u32 pixfmt = pix->pixelformat;
        const struct soc_camera_format_xlate *xlate;
-       unsigned int ceu_sub_width, ceu_sub_height;
+       /* Keep Compiler Happy */
+       unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
        u16 scale_v, scale_h;
        int ret;
        bool image_mode;
@@ -1569,8 +1586,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
 
        /* Done with the camera. Now see if we can improve the result */
 
-       dev_geo(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
-               ret, mf.width, mf.height, pix->width, pix->height);
+       dev_geo(dev, "fmt %ux%u, requested %ux%u\n",
+               mf.width, mf.height, pix->width, pix->height);
        if (ret < 0)
                return ret;
 
@@ -1634,6 +1651,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        int width, height;
        int ret;
 
+       dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+                pixfmt, pix->width, pix->height);
+
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
                dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
@@ -1660,7 +1680,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        mf.code         = xlate->code;
        mf.colorspace   = pix->colorspace;
 
-       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
        if (ret < 0)
                return ret;
 
@@ -1684,7 +1704,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                         */
                        mf.width = 2560;
                        mf.height = 1920;
-                       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+                       ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+                                                        try_mbus_fmt, &mf);
                        if (ret < 0) {
                                /* Shouldn't actually happen... */
                                dev_err(icd->dev.parent,
@@ -1699,6 +1720,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                        pix->height = height;
        }
 
+       dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+               __func__, ret, pix->pixelformat, pix->width, pix->height);
+
        return ret;
 }
 
@@ -1853,6 +1877,30 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .num_controls   = ARRAY_SIZE(sh_mobile_ceu_controls),
 };
 
+struct bus_wait {
+       struct notifier_block   notifier;
+       struct completion       completion;
+       struct device           *dev;
+};
+
+static int bus_notify(struct notifier_block *nb,
+                     unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
+
+       if (wait->dev != dev)
+               return NOTIFY_DONE;
+
+       switch (action) {
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               /* Protect from module unloading */
+               wait_for_completion(&wait->completion);
+               return NOTIFY_OK;
+       }
+       return NOTIFY_DONE;
+}
+
 static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
 {
        struct sh_mobile_ceu_dev *pcdev;
@@ -1860,6 +1908,11 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
        void __iomem *base;
        unsigned int irq;
        int err = 0;
+       struct bus_wait wait = {
+               .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
+               .notifier.notifier_call = bus_notify,
+       };
+       struct device *csi2;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
@@ -1931,12 +1984,54 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
        pcdev->ici.drv_name = dev_name(&pdev->dev);
        pcdev->ici.ops = &sh_mobile_ceu_host_ops;
 
+       /* CSI2 interfacing */
+       csi2 = pcdev->pdata->csi2_dev;
+       if (csi2) {
+               wait.dev = csi2;
+
+               err = bus_register_notifier(&platform_bus_type, &wait.notifier);
+               if (err < 0)
+                       goto exit_free_clk;
+
+               /*
+                * From this point the driver module will not unload, until
+                * we complete the completion.
+                */
+
+               if (!csi2->driver || !csi2->driver->owner) {
+                       complete(&wait.completion);
+                       /* Either too late, or probing failed */
+                       bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+                       err = -ENXIO;
+                       goto exit_free_clk;
+               }
+
+               /*
+                * The module is still loaded, in the worst case it is hanging
+                * in device release on our completion. So, _now_ dereferencing
+                * the "owner" is safe!
+                */
+
+               err = try_module_get(csi2->driver->owner);
+
+               /* Let notifier complete, if it has been locked */
+               complete(&wait.completion);
+               bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+               if (!err) {
+                       err = -ENODEV;
+                       goto exit_free_clk;
+               }
+       }
+
        err = soc_camera_host_register(&pcdev->ici);
        if (err)
-               goto exit_free_clk;
+               goto exit_module_put;
 
        return 0;
 
+exit_module_put:
+       if (csi2 && csi2->driver)
+               module_put(csi2->driver->owner);
 exit_free_clk:
        pm_runtime_disable(&pdev->dev);
        free_irq(pcdev->irq, pcdev);
@@ -1956,6 +2051,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
                                        struct sh_mobile_ceu_dev, ici);
+       struct device *csi2 = pcdev->pdata->csi2_dev;
 
        soc_camera_host_unregister(soc_host);
        pm_runtime_disable(&pdev->dev);
@@ -1963,7 +2059,10 @@ 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);
+       if (csi2 && csi2->driver)
+               module_put(csi2->driver->owner);
        kfree(pcdev);
+
        return 0;
 }
 
@@ -1995,6 +2094,8 @@ static struct platform_driver sh_mobile_ceu_driver = {
 
 static int __init sh_mobile_ceu_init(void)
 {
+       /* Whatever return code */
+       request_module("sh_mobile_csi2");
        return platform_driver_register(&sh_mobile_ceu_driver);
 }
 
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
new file mode 100644 (file)
index 0000000..84a6468
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define SH_CSI2_TREF   0x00
+#define SH_CSI2_SRST   0x04
+#define SH_CSI2_PHYCNT 0x08
+#define SH_CSI2_CHKSUM 0x0C
+#define SH_CSI2_VCDT   0x10
+
+struct sh_csi2 {
+       struct v4l2_subdev              subdev;
+       struct list_head                list;
+       struct notifier_block           notifier;
+       unsigned int                    irq;
+       void __iomem                    *base;
+       struct platform_device          *pdev;
+       struct sh_csi2_client_config    *client;
+};
+
+static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_mbus_framefmt *mf)
+{
+       struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+       struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+
+       if (mf->width > 8188)
+               mf->width = 8188;
+       else if (mf->width & 1)
+               mf->width &= ~1;
+
+       switch (pdata->type) {
+       case SH_CSI2C:
+               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_SBGGR8_1X8:
+               case V4L2_MBUS_FMT_SGRBG8_1X8:
+                       break;
+               default:
+                       /* All MIPI CSI-2 devices must support one of primary formats */
+                       mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+               }
+               break;
+       case SH_CSI2I:
+               switch (mf->code) {
+               case V4L2_MBUS_FMT_GREY8_1X8:           /* RAW8 */
+               case V4L2_MBUS_FMT_SBGGR8_1X8:
+               case V4L2_MBUS_FMT_SGRBG8_1X8:
+               case V4L2_MBUS_FMT_SBGGR10_1X10:        /* RAW10 */
+               case V4L2_MBUS_FMT_SBGGR12_1X12:        /* RAW12 */
+                       break;
+               default:
+                       /* All MIPI CSI-2 devices must support one of primary formats */
+                       mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * We have done our best in try_fmt to try and tell the sensor, which formats
+ * we support. If now the configuration is unsuitable for us we can only
+ * error out.
+ */
+static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+       u32 tmp = (priv->client->channel & 3) << 8;
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+       if (mf->width > 8188 || mf->width & 1)
+               return -EINVAL;
+
+       switch (mf->code) {
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               tmp |= 0x1e;    /* YUV422 8 bit */
+               break;
+       case V4L2_MBUS_FMT_YUYV8_1_5X8:
+               tmp |= 0x18;    /* YUV420 8 bit */
+               break;
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+               tmp |= 0x21;    /* RGB555 */
+               break;
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+               tmp |= 0x22;    /* RGB565 */
+               break;
+       case V4L2_MBUS_FMT_GREY8_1X8:
+       case V4L2_MBUS_FMT_SBGGR8_1X8:
+       case V4L2_MBUS_FMT_SGRBG8_1X8:
+               tmp |= 0x2a;    /* RAW8 */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       iowrite32(tmp, priv->base + SH_CSI2_VCDT);
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
+       .s_mbus_fmt     = sh_csi2_s_fmt,
+       .try_mbus_fmt   = sh_csi2_try_fmt,
+};
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+       .core   = &sh_csi2_subdev_core_ops,
+       .video  = &sh_csi2_subdev_video_ops,
+};
+
+static void sh_csi2_hwinit(struct sh_csi2 *priv)
+{
+       struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+       __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+       /* Reflect registers immediately */
+       iowrite32(0x00000001, priv->base + SH_CSI2_TREF);
+       /* reset CSI2 harware */
+       iowrite32(0x00000001, priv->base + SH_CSI2_SRST);
+       udelay(5);
+       iowrite32(0x00000000, priv->base + SH_CSI2_SRST);
+
+       if (priv->client->lanes & 3)
+               tmp |= priv->client->lanes & 3;
+       else
+               /* Default - both lanes */
+               tmp |= 3;
+
+       if (priv->client->phy == SH_CSI2_PHY_MAIN)
+               tmp |= 0x8000;
+
+       iowrite32(tmp, priv->base + SH_CSI2_PHYCNT);
+
+       tmp = 0;
+       if (pdata->flags & SH_CSI2_ECC)
+               tmp |= 2;
+       if (pdata->flags & SH_CSI2_CRC)
+               tmp |= 1;
+       iowrite32(tmp, priv->base + SH_CSI2_CHKSUM);
+}
+
+static int sh_csi2_set_bus_param(struct soc_camera_device *icd,
+                                unsigned long flags)
+{
+       return 0;
+}
+
+static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
+{
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+       const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int sh_csi2_notify(struct notifier_block *nb,
+                         unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct soc_camera_device *icd = to_soc_camera_dev(dev);
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
+       struct sh_csi2 *priv =
+               container_of(nb, struct sh_csi2, notifier);
+       struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+       int ret, i;
+
+       for (i = 0; i < pdata->num_clients; i++)
+               if (&pdata->clients[i].pdev->dev == icd->pdev)
+                       break;
+
+       dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
+
+       if (i == pdata->num_clients)
+               return NOTIFY_DONE;
+
+       switch (action) {
+       case BUS_NOTIFY_BOUND_DRIVER:
+               snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
+                        dev_name(v4l2_dev->dev), ".mipi-csi");
+               ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
+               dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+               if (ret < 0)
+                       return NOTIFY_DONE;
+
+               priv->client = pdata->clients + i;
+
+               icd->ops->set_bus_param         = sh_csi2_set_bus_param;
+               icd->ops->query_bus_param       = sh_csi2_query_bus_param;
+
+               pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
+
+               sh_csi2_hwinit(priv);
+               break;
+       case BUS_NOTIFY_UNBIND_DRIVER:
+               priv->client = NULL;
+
+               /* Driver is about to be unbound */
+               icd->ops->set_bus_param         = NULL;
+               icd->ops->query_bus_param       = NULL;
+
+               v4l2_device_unregister_subdev(&priv->subdev);
+
+               pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static __devinit int sh_csi2_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       unsigned int irq;
+       int ret;
+       struct sh_csi2 *priv;
+       /* Platform data specify the PHY, lanes, ECC, CRC */
+       struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       /* Interrupt unused so far */
+       irq = platform_get_irq(pdev, 0);
+
+       if (!res || (int)irq <= 0 || !pdata) {
+               dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+               return -ENODEV;
+       }
+
+       /* TODO: Add support for CSI2I. Careful: different register layout! */
+       if (pdata->type != SH_CSI2C) {
+               dev_err(&pdev->dev, "Only CSI2C supported ATM.\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->irq = irq;
+       priv->notifier.notifier_call = sh_csi2_notify;
+
+       /* We MUST attach after the MIPI sensor */
+       ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
+               goto ernotify;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+               dev_err(&pdev->dev, "CSI2 register region already claimed\n");
+               ret = -EBUSY;
+               goto ereqreg;
+       }
+
+       priv->base = ioremap(res->start, resource_size(res));
+       if (!priv->base) {
+               ret = -ENXIO;
+               dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
+               goto eremap;
+       }
+
+       priv->pdev = pdev;
+
+       v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
+       v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+       platform_set_drvdata(pdev, priv);
+
+       pm_runtime_enable(&pdev->dev);
+
+       dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+       return 0;
+
+eremap:
+       release_mem_region(res->start, resource_size(res));
+ereqreg:
+       bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+ernotify:
+       kfree(priv);
+
+       return ret;
+}
+
+static __devexit int sh_csi2_remove(struct platform_device *pdev)
+{
+       struct sh_csi2 *priv = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+       pm_runtime_disable(&pdev->dev);
+       iounmap(priv->base);
+       release_mem_region(res->start, resource_size(res));
+       platform_set_drvdata(pdev, NULL);
+       kfree(priv);
+
+       return 0;
+}
+
+static struct platform_driver __refdata sh_csi2_pdrv = {
+       .remove  = __devexit_p(sh_csi2_remove),
+       .driver  = {
+               .name   = "sh-mobile-csi2",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sh_csi2_init(void)
+{
+       return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
+}
+
+static void __exit sh_csi2_exit(void)
+{
+       platform_driver_unregister(&sh_csi2_pdrv);
+}
+
+module_init(sh_csi2_init);
+module_exit(sh_csi2_exit);
+
+MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh-mobile-csi2");
index f5b892a2a8eed6c506f00f2cfae291cf7f9a07de..d394187eb701d04aa81ebe4a4aff4966e5e63257 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 #include <linux/videodev2.h>
 
@@ -57,7 +58,7 @@ enum sh_vou_status {
 };
 
 #define VOU_MAX_IMAGE_WIDTH    720
-#define VOU_MAX_IMAGE_HEIGHT   480
+#define VOU_MAX_IMAGE_HEIGHT   576
 
 struct sh_vou_device {
        struct v4l2_device v4l2_dev;
@@ -527,20 +528,17 @@ struct sh_vou_geometry {
 static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
 {
        /* The compiler cannot know, that best and idx will indeed be set */
-       unsigned int best_err = UINT_MAX, best = 0, width_max, height_max;
+       unsigned int best_err = UINT_MAX, best = 0, img_height_max;
        int i, idx = 0;
 
-       if (std & V4L2_STD_525_60) {
-               width_max = 858;
-               height_max = 262;
-       } else {
-               width_max = 864;
-               height_max = 312;
-       }
+       if (std & V4L2_STD_525_60)
+               img_height_max = 480;
+       else
+               img_height_max = 576;
 
        /* Image width must be a multiple of 4 */
        v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
-                             &geo->in_height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+                             &geo->in_height, 0, img_height_max, 1, 0);
 
        /* Select scales to come as close as possible to the output image */
        for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
@@ -573,7 +571,7 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
                unsigned int found = geo->output.height * vou_scale_v_den[i] /
                        vou_scale_v_num[i];
 
-               if (found > VOU_MAX_IMAGE_HEIGHT)
+               if (found > img_height_max)
                        /* scales increase */
                        break;
 
@@ -597,15 +595,18 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
  */
 static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
 {
-       unsigned int best_err = UINT_MAX, best, width_max, height_max;
+       unsigned int best_err = UINT_MAX, best, width_max, height_max,
+               img_height_max;
        int i, idx;
 
        if (std & V4L2_STD_525_60) {
                width_max = 858;
                height_max = 262 * 2;
+               img_height_max = 480;
        } else {
                width_max = 864;
                height_max = 312 * 2;
+               img_height_max = 576;
        }
 
        /* Select scales to come as close as possible to the output image */
@@ -644,7 +645,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
                unsigned int found = geo->in_height * vou_scale_v_num[i] /
                        vou_scale_v_den[i];
 
-               if (found > VOU_MAX_IMAGE_HEIGHT)
+               if (found > img_height_max)
                        /* scales increase */
                        break;
 
@@ -673,11 +674,12 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
        struct video_device *vdev = video_devdata(file);
        struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
        struct v4l2_pix_format *pix = &fmt->fmt.pix;
+       unsigned int img_height_max;
        int pix_idx;
        struct sh_vou_geometry geo;
        struct v4l2_mbus_framefmt mbfmt = {
                /* Revisit: is this the correct code? */
-               .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+               .code = V4L2_MBUS_FMT_YUYV8_2X8,
                .field = V4L2_FIELD_INTERLACED,
                .colorspace = V4L2_COLORSPACE_SMPTE170M,
        };
@@ -701,9 +703,14 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
        if (pix_idx == ARRAY_SIZE(vou_fmt))
                return -EINVAL;
 
+       if (vou_dev->std & V4L2_STD_525_60)
+               img_height_max = 480;
+       else
+               img_height_max = 576;
+
        /* Image width must be a multiple of 4 */
        v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
-                             &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+                             &pix->height, 0, img_height_max, 1, 0);
 
        geo.in_width = pix->width;
        geo.in_height = pix->height;
@@ -724,8 +731,8 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
 
        /* Sanity checks */
        if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
-           (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
-           mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+           (unsigned)mbfmt.height > img_height_max ||
+           mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
                return -EIO;
 
        if (mbfmt.width != geo.output.width ||
@@ -936,10 +943,11 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
        struct sh_vou_geometry geo;
        struct v4l2_mbus_framefmt mbfmt = {
                /* Revisit: is this the correct code? */
-               .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+               .code = V4L2_MBUS_FMT_YUYV8_2X8,
                .field = V4L2_FIELD_INTERLACED,
                .colorspace = V4L2_COLORSPACE_SMPTE170M,
        };
+       unsigned int img_height_max;
        int ret;
 
        dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
@@ -948,14 +956,19 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
        if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
 
+       if (vou_dev->std & V4L2_STD_525_60)
+               img_height_max = 480;
+       else
+               img_height_max = 576;
+
        v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
-                             &rect->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+                             &rect->height, 0, img_height_max, 1, 0);
 
        if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
                rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
 
-       if (rect->height + rect->top > VOU_MAX_IMAGE_HEIGHT)
-               rect->top = VOU_MAX_IMAGE_HEIGHT - rect->height;
+       if (rect->height + rect->top > img_height_max)
+               rect->top = img_height_max - rect->height;
 
        geo.output = *rect;
        geo.in_width = pix->width;
@@ -980,8 +993,8 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
 
        /* Sanity checks */
        if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
-           (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
-           mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+           (unsigned)mbfmt.height > img_height_max ||
+           mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
                return -EIO;
 
        geo.output.width = mbfmt.width;
@@ -1329,13 +1342,13 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
        rect->left              = 0;
        rect->top               = 0;
        rect->width             = VOU_MAX_IMAGE_WIDTH;
-       rect->height            = VOU_MAX_IMAGE_HEIGHT;
+       rect->height            = 480;
        pix->width              = VOU_MAX_IMAGE_WIDTH;
-       pix->height             = VOU_MAX_IMAGE_HEIGHT;
+       pix->height             = 480;
        pix->pixelformat        = V4L2_PIX_FMT_YVYU;
        pix->field              = V4L2_FIELD_NONE;
        pix->bytesperline       = VOU_MAX_IMAGE_WIDTH * 2;
-       pix->sizeimage          = VOU_MAX_IMAGE_WIDTH * 2 * VOU_MAX_IMAGE_HEIGHT;
+       pix->sizeimage          = VOU_MAX_IMAGE_WIDTH * 2 * 480;
        pix->colorspace         = V4L2_COLORSPACE_SMPTE170M;
 
        region = request_mem_region(reg_res->start, resource_size(reg_res),
index 475757bfd7ba5bbd0cff11ecf8ab4f963d5174f9..f2032939fd4b728d0d7465d03da5ec587087c52f 100644 (file)
@@ -1107,13 +1107,14 @@ static int soc_camera_resume(struct device *dev)
        return ret;
 }
 
-static struct bus_type soc_camera_bus_type = {
+struct bus_type soc_camera_bus_type = {
        .name           = "soc-camera",
        .probe          = soc_camera_probe,
        .remove         = soc_camera_remove,
        .suspend        = soc_camera_suspend,
        .resume         = soc_camera_resume,
 };
+EXPORT_SYMBOL_GPL(soc_camera_bus_type);
 
 static struct device_driver ic_drv = {
        .name   = "camera",
index 248c986f0989744bce6497d699fe4d43d038b850..bf406e89c992b6515ed7c27f8f87ef6577202d6e 100644 (file)
@@ -56,8 +56,8 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
        return p->bus_param;
 }
 
-static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
-                                      struct v4l2_mbus_framefmt *mf)
+static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
+                                       struct v4l2_mbus_framefmt *mf)
 {
        struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
 
@@ -65,6 +65,7 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
        mf->height      = p->format.height;
        mf->code        = p->format.code;
        mf->colorspace  = p->format.colorspace;
+       mf->field       = p->format.field;
 
        return 0;
 }
@@ -83,10 +84,45 @@ static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int ind
        return 0;
 }
 
+static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
+                                     struct v4l2_crop *a)
+{
+       struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+       a->c.left       = 0;
+       a->c.top        = 0;
+       a->c.width      = p->format.width;
+       a->c.height     = p->format.height;
+       a->type         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       return 0;
+}
+
+static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
+                                      struct v4l2_cropcap *a)
+{
+       struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+       a->bounds.left                  = 0;
+       a->bounds.top                   = 0;
+       a->bounds.width                 = p->format.width;
+       a->bounds.height                = p->format.height;
+       a->defrect                      = a->bounds;
+       a->type                         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
 static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
        .s_stream       = soc_camera_platform_s_stream,
-       .try_mbus_fmt   = soc_camera_platform_try_fmt,
        .enum_mbus_fmt  = soc_camera_platform_enum_fmt,
+       .cropcap        = soc_camera_platform_cropcap,
+       .g_crop         = soc_camera_platform_g_crop,
+       .try_mbus_fmt   = soc_camera_platform_fill_fmt,
+       .g_mbus_fmt     = soc_camera_platform_fill_fmt,
+       .s_mbus_fmt     = soc_camera_platform_fill_fmt,
 };
 
 static struct v4l2_subdev_ops platform_subdev_ops = {
index 8b63b6545e7657827a054505ffd5d109b2c830a2..91391214c682d46f52bae13eb53a3c7f37f2f347 100644 (file)
 #define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)
 
 static const struct soc_mbus_pixelfmt mbus_fmt[] = {
-       [MBUS_IDX(YUYV8_2X8_LE)] = {
+       [MBUS_IDX(YUYV8_2X8)] = {
                .fourcc                 = V4L2_PIX_FMT_YUYV,
                .name                   = "YUYV",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(YVYU8_2X8_LE)] = {
+       [MBUS_IDX(YVYU8_2X8)] = {
                .fourcc                 = V4L2_PIX_FMT_YVYU,
                .name                   = "YVYU",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(YUYV8_2X8_BE)] = {
+       [MBUS_IDX(UYVY8_2X8)] = {
                .fourcc                 = V4L2_PIX_FMT_UYVY,
                .name                   = "UYVY",
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(YVYU8_2X8_BE)] = {
+       [MBUS_IDX(VYUY8_2X8)] = {
                .fourcc                 = V4L2_PIX_FMT_VYUY,
                .name                   = "VYUY",
                .bits_per_sample        = 8,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
deleted file mode 100644 (file)
index 5938ad8..0000000
+++ /dev/null
@@ -1,1565 +0,0 @@
-/*
- *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
- *
- * Thanks to STMicroelectronics for information on the usb commands, and
- * to Steve Miller at STM for his help and encouragement while I was
- * writing this driver.
- *
- * This driver is based heavily on the
- * 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.
- *
- * History:
- * ver 0.1 October, 2001. Initial attempt.
- *
- * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
- *                         function, made more stable (?)
- *
- * ver 0.21 Nov, 2001.     Added gamma correction and white balance,
- *                         due to Alexander Schwartz. Still trying to
- *                         improve stablility. Moved stuff into stv680.h
- *
- * ver 0.22 Nov, 2001.    Added sharpen function (by Michael Sweet,
- *                         mike@easysw.com) from GIMP, also used in pencam.
- *                         Simple, fast, good integer math routine.
- *
- * ver 0.23 Dec, 2001 (gkh)
- *                        Took out sharpen function, ran code through
- *                        Lindent, and did other minor tweaks to get
- *                        things to work properly with 2.5.1
- *
- * ver 0.24 Jan, 2002 (kjs)
- *                         Fixed the problem with webcam crashing after
- *                         two pictures. Changed the way pic is halved to
- *                         improve quality. Got rid of green line around
- *                         frame. Fix brightness reset when changing size
- *                         bug. Adjusted gamma filters slightly.
- *
- * ver 0.25 Jan, 2002 (kjs)
- *                        Fixed a bug in which the driver sometimes attempted
- *                        to set to a non-supported size. This allowed
- *                        gnomemeeting to work.
- *                        Fixed proc entry removal bug.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-#include <linux/errno.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#include "stv680.h"
-
-static int video_nr = -1;
-
-static int swapRGB;    /* 0 = default for auto select */
-
-/* 0 = default to allow auto select; -1 = swap never, +1 = swap always */
-static int swapRGB_on;
-
-static unsigned int debug;
-
-#define PDEBUG(level, fmt, args...) \
-       do { \
-       if (debug >= level)     \
-               printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt,      \
-                       __func__, __LINE__ , ## args);  \
-       } while (0)
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.25"
-#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
-#define DRIVER_DESC "STV0680 USB Camera Driver"
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (debug, "Debug enabled or not");
-module_param(swapRGB_on, int, 0);
-MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
-module_param(video_nr, int, 0);
-
-/********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
- ********************************************************************/
-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);
-}
-
-
-/*********************************************************************
- * pencam read/write functions
- ********************************************************************/
-
-static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
-{
-       int ret = -1;
-
-       switch (set) {
-       case 0:         /*  0xc1  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_rcvctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 1:         /*  0x41  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_sndctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 2:         /*  0x80  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_rcvctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_IN | USB_RECIP_DEVICE),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 3:         /*  0x40  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_sndctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       }
-       if ((ret < 0) && (req != 0x0a)) {
-               PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
-       }
-       return ret;
-}
-
-static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
-{
-
-       if (configuration != dev->udev->actconfig->desc.bConfigurationValue
-                       || usb_reset_configuration (dev->udev) < 0) {
-               PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
-               return -1;
-       }
-       if (usb_set_interface (dev->udev, interface, alternate) < 0) {
-               PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
-               return -1;
-       }
-       return 0;
-}
-
-static int stv_stop_video (struct usb_stv *dev)
-{
-       int i;
-       unsigned char *buf;
-
-       buf = kmalloc (40, GFP_KERNEL);
-       if (buf == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-
-       /* this is a high priority command; it stops all lower order commands */
-       if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
-               i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);   /* Get Last Error; 2 = busy */
-               PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
-       } else {
-               PDEBUG (1, "STV(i): Camera reset to idle mode.");
-       }
-
-       if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
-               PDEBUG (1, "STV(e): Reset config during exit failed");
-
-       /*  get current mode  */
-       buf[0] = 0xf0;
-       if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)     /* get mode */
-               PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
-       if (dev->origMode != buf[0]) {
-               memset (buf, 0, 8);
-               buf[0] = (unsigned char) dev->origMode;
-               if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
-                       PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
-                       i = -1;
-               }
-               buf[0] = 0xf0;
-               i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
-               if ((i != 0x08) || (buf[0] != dev->origMode)) {
-                       PDEBUG (0, "STV(e): camera NOT set to original resolution.");
-                       i = -1;
-               } else
-                       PDEBUG (0, "STV(i): Camera set to original resolution");
-       }
-       /* origMode */
-       kfree(buf);
-       return i;
-}
-
-static int stv_set_video_mode (struct usb_stv *dev)
-{
-       int i, stop_video = 1;
-       unsigned char *buf;
-
-       buf = kmalloc (40, GFP_KERNEL);
-       if (buf == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-
-       if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
-               kfree(buf);
-               return i;
-       }
-
-       i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
-       if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
-               PDEBUG (1, "STV(e): Could not get descriptor 0100.");
-               goto error;
-       }
-
-       /*  set alternate interface 1 */
-       if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
-               goto error;
-
-       if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
-               goto error;
-       PDEBUG (1, "STV(i): Setting video mode.");
-       /*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
-       if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
-               stop_video = 0;
-               goto error;
-       }
-       goto exit;
-
-error:
-       kfree(buf);
-       if (stop_video == 1)
-               stv_stop_video (dev);
-       return -1;
-
-exit:
-       kfree(buf);
-       return 0;
-}
-
-static int stv_init (struct usb_stv *stv680)
-{
-       int i = 0;
-       unsigned char *buffer;
-       unsigned long int bufsize;
-
-       buffer = kzalloc (40, GFP_KERNEL);
-       if (buffer == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-       udelay (100);
-
-       /* set config 1, interface 0, alternate 0 */
-       if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
-               kfree(buffer);
-               PDEBUG (0, "STV(e): set config 1,0,0 failed");
-               return -1;
-       }
-       /* ping camera to be sure STV0680 is present */
-       if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
-               goto error;
-       if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
-               PDEBUG (1, "STV(e): camera ping failed!!");
-               goto error;
-       }
-
-       /* get camera descriptor */
-       if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
-               goto error;
-       i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
-       if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
-               PDEBUG (1, "STV(e): Could not get descriptor 0200.");
-               goto error;
-       }
-       if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-               goto error;
-
-       stv680->SupportedModes = buffer[7];
-       i = stv680->SupportedModes;
-       stv680->CIF = 0;
-       stv680->VGA = 0;
-       stv680->QVGA = 0;
-       if (i & 1)
-               stv680->CIF = 1;
-       if (i & 2)
-               stv680->VGA = 1;
-       if (i & 8)
-               stv680->QVGA = 1;
-       if (stv680->SupportedModes == 0) {
-               PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
-               i = -1;
-               goto error;
-       } else {
-               if (stv680->CIF)
-                       PDEBUG (0, "STV(i): CIF is supported");
-               if (stv680->QVGA)
-                       PDEBUG (0, "STV(i): QVGA is supported");
-       }
-       /* FW rev, ASIC rev, sensor ID  */
-       PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
-       PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
-       PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
-
-       /*  set alternate interface 1 */
-       if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
-               goto error;
-
-       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
-               goto error;
-       i = buffer[3];
-       PDEBUG (0, "STV(i): Camera has %i pictures.", i);
-
-       /*  get current mode */
-       if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
-               goto error;
-       stv680->origMode = buffer[0];   /* 01 = VGA, 03 = QVGA, 00 = CIF */
-
-       /* This will attemp CIF mode, if supported. If not, set to QVGA  */
-       memset (buffer, 0, 8);
-       if (stv680->CIF)
-               buffer[0] = 0x00;
-       else if (stv680->QVGA)
-               buffer[0] = 0x03;
-       if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
-               PDEBUG (0, "STV(i): Set_Camera_Mode failed");
-               i = -1;
-               goto error;
-       }
-       buffer[0] = 0xf0;
-       stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
-       if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
-               PDEBUG (0, "STV(e): Error setting camera video mode!");
-               i = -1;
-               goto error;
-       } else {
-               if (buffer[0] == 0) {
-                       stv680->VideoMode = 0x0000;
-                       PDEBUG (0, "STV(i): Video Mode set to CIF");
-               }
-               if (buffer[0] == 0x03) {
-                       stv680->VideoMode = 0x0300;
-                       PDEBUG (0, "STV(i): Video Mode set to QVGA");
-               }
-       }
-       if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
-               goto error;
-       bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
-       stv680->cwidth = (buffer[4] << 8) | (buffer[5]);        /* ->camera = 322, 356, 644  */
-       stv680->cheight = (buffer[6] << 8) | (buffer[7]);       /* ->camera = 242, 292, 484  */
-       stv680->origGain = buffer[12];
-
-       goto exit;
-
-error:
-       i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);     /* Get Last Error */
-       PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
-       kfree(buffer);
-       return -1;
-
-exit:
-       kfree(buffer);
-
-       /* video = 320x240, 352x288 */
-       if (stv680->CIF == 1) {
-               stv680->maxwidth = 352;
-               stv680->maxheight = 288;
-               stv680->vwidth = 352;
-               stv680->vheight = 288;
-       }
-       if (stv680->QVGA == 1) {
-               stv680->maxwidth = 320;
-               stv680->maxheight = 240;
-               stv680->vwidth = 320;
-               stv680->vheight = 240;
-       }
-
-       stv680->rawbufsize = bufsize;   /* must be ./. by 8 */
-       stv680->maxframesize = bufsize * 3;     /* RGB size */
-       PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
-       PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
-
-       /* some default values */
-       stv680->bulk_in_endpointAddr = 0x82;
-       stv680->dropped = 0;
-       stv680->error = 0;
-       stv680->framecount = 0;
-       stv680->readcount = 0;
-       stv680->streaming = 0;
-       /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
-       stv680->brightness = 32767;
-       stv680->chgbright = 0;
-       stv680->whiteness = 0;  /* only for greyscale */
-       stv680->colour = 32767;
-       stv680->contrast = 32767;
-       stv680->hue = 32767;
-       stv680->palette = STV_VIDEO_PALETTE;
-       stv680->depth = 24;     /* rgb24 bits */
-       if ((swapRGB_on == 0) && (swapRGB == 0))
-               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
-       else if ((swapRGB_on == 0) && (swapRGB == 1))
-               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
-       else if (swapRGB_on == 1)
-               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
-       else if (swapRGB_on == -1)
-               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
-
-       if (stv_set_video_mode (stv680) < 0) {
-               PDEBUG (0, "STV(e): Could not set video mode in stv_init");
-               return -1;
-       }
-
-       return 0;
-}
-
-/***************** last of pencam  routines  *******************/
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-#define stv680_file(name, variable, field)                             \
-static ssize_t show_##name(struct device *class_dev,                   \
-                          struct device_attribute *attr, char *buf)    \
-{                                                                      \
-       struct video_device *vdev = to_video_device(class_dev);         \
-       struct usb_stv *stv = video_get_drvdata(vdev);                  \
-       return sprintf(buf, field, stv->variable);                      \
-}                                                                      \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-stv680_file(model, camera_name, "%s\n");
-stv680_file(in_use, user, "%d\n");
-stv680_file(streaming, streaming, "%d\n");
-stv680_file(palette, palette, "%i\n");
-stv680_file(frames_total, readcount, "%d\n");
-stv680_file(frames_read, framecount, "%d\n");
-stv680_file(packets_dropped, dropped, "%d\n");
-stv680_file(decoding_errors, error, "%d\n");
-
-static int stv680_create_sysfs_files(struct video_device *vdev)
-{
-       int rc;
-
-       rc = device_create_file(&vdev->dev, &dev_attr_model);
-       if (rc) goto err;
-       rc = device_create_file(&vdev->dev, &dev_attr_in_use);
-       if (rc) goto err_model;
-       rc = device_create_file(&vdev->dev, &dev_attr_streaming);
-       if (rc) goto err_inuse;
-       rc = device_create_file(&vdev->dev, &dev_attr_palette);
-       if (rc) goto err_stream;
-       rc = device_create_file(&vdev->dev, &dev_attr_frames_total);
-       if (rc) goto err_pal;
-       rc = device_create_file(&vdev->dev, &dev_attr_frames_read);
-       if (rc) goto err_framtot;
-       rc = device_create_file(&vdev->dev, &dev_attr_packets_dropped);
-       if (rc) goto err_framread;
-       rc = device_create_file(&vdev->dev, &dev_attr_decoding_errors);
-       if (rc) goto err_dropped;
-
-       return 0;
-
-err_dropped:
-       device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
-err_framread:
-       device_remove_file(&vdev->dev, &dev_attr_frames_read);
-err_framtot:
-       device_remove_file(&vdev->dev, &dev_attr_frames_total);
-err_pal:
-       device_remove_file(&vdev->dev, &dev_attr_palette);
-err_stream:
-       device_remove_file(&vdev->dev, &dev_attr_streaming);
-err_inuse:
-       device_remove_file(&vdev->dev, &dev_attr_in_use);
-err_model:
-       device_remove_file(&vdev->dev, &dev_attr_model);
-err:
-       PDEBUG(0, "STV(e): Could not create sysfs files");
-       return rc;
-}
-
-static void stv680_remove_sysfs_files(struct video_device *vdev)
-{
-       device_remove_file(&vdev->dev, &dev_attr_model);
-       device_remove_file(&vdev->dev, &dev_attr_in_use);
-       device_remove_file(&vdev->dev, &dev_attr_streaming);
-       device_remove_file(&vdev->dev, &dev_attr_palette);
-       device_remove_file(&vdev->dev, &dev_attr_frames_total);
-       device_remove_file(&vdev->dev, &dev_attr_frames_read);
-       device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
-       device_remove_file(&vdev->dev, &dev_attr_decoding_errors);
-}
-
-/********************************************************************
- * Camera control
- *******************************************************************/
-
-static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-       /* This sets values for v4l interface. max/min = 65535/0  */
-
-       p->brightness = stv680->brightness;
-       p->whiteness = stv680->whiteness;       /* greyscale */
-       p->colour = stv680->colour;
-       p->contrast = stv680->contrast;
-       p->hue = stv680->hue;
-       p->palette = stv680->palette;
-       p->depth = stv680->depth;
-       return 0;
-}
-
-static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-       /* See above stv680_get_pict  */
-
-       if (p->palette != STV_VIDEO_PALETTE) {
-               PDEBUG (2, "STV(e): Palette set error in _set_pic");
-               return 1;
-       }
-
-       if (stv680->brightness != p->brightness) {
-               stv680->chgbright = 1;
-               stv680->brightness = p->brightness;
-       }
-
-       stv680->whiteness = p->whiteness;       /* greyscale */
-       stv680->colour = p->colour;
-       stv680->contrast = p->contrast;
-       stv680->hue = p->hue;
-       stv680->palette = p->palette;
-       stv680->depth = p->depth;
-
-       return 0;
-}
-
-static void stv680_video_irq (struct urb *urb)
-{
-       struct usb_stv *stv680 = urb->context;
-       int length = urb->actual_length;
-
-       if (length < stv680->rawbufsize)
-               PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
-
-       /* ohoh... */
-       if (!stv680->streaming)
-               return;
-
-       if (!stv680->udev) {
-               PDEBUG (0, "STV(e): device vapourished in video_irq");
-               return;
-       }
-
-       /* 0 sized packets happen if we are to fast, but sometimes the camera
-          keeps sending them forever...
-        */
-       if (length && !urb->status) {
-               stv680->nullpackets = 0;
-               switch (stv680->scratch[stv680->scratch_next].state) {
-               case BUFFER_READY:
-               case BUFFER_BUSY:
-                       stv680->dropped++;
-                       break;
-
-               case BUFFER_UNUSED:
-                       memcpy (stv680->scratch[stv680->scratch_next].data,
-                               (unsigned char *) urb->transfer_buffer, length);
-                       stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
-                       stv680->scratch[stv680->scratch_next].length = length;
-                       if (waitqueue_active (&stv680->wq)) {
-                               wake_up_interruptible (&stv680->wq);
-                       }
-                       stv680->scratch_overflow = 0;
-                       stv680->scratch_next++;
-                       if (stv680->scratch_next >= STV680_NUMSCRATCH)
-                               stv680->scratch_next = 0;
-                       break;
-               }               /* switch  */
-       } else {
-               stv680->nullpackets++;
-               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-                       if (waitqueue_active (&stv680->wq)) {
-                               wake_up_interruptible (&stv680->wq);
-                       }
-               }
-       }                       /*  if - else */
-
-       /* Resubmit urb for new data */
-       urb->status = 0;
-       urb->dev = stv680->udev;
-       if (usb_submit_urb (urb, GFP_ATOMIC))
-               PDEBUG (0, "STV(e): urb burned down in video irq");
-       return;
-}                              /*  _video_irq  */
-
-static int stv680_start_stream (struct usb_stv *stv680)
-{
-       struct urb *urb;
-       int err = 0, i;
-
-       stv680->streaming = 1;
-
-       /* Do some memory allocation */
-       for (i = 0; i < STV680_NUMFRAMES; i++) {
-               stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
-               stv680->frame[i].curpix = 0;
-       }
-       /* packet size = 4096  */
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-               if (stv680->sbuf[i].data == NULL) {
-                       PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
-                       goto nomem_err;
-               }
-       }
-
-       stv680->scratch_next = 0;
-       stv680->scratch_use = 0;
-       stv680->scratch_overflow = 0;
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-               if (stv680->scratch[i].data == NULL) {
-                       PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
-                       goto nomem_err;
-               }
-               stv680->scratch[i].state = BUFFER_UNUSED;
-       }
-
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               urb = usb_alloc_urb (0, GFP_KERNEL);
-               if (!urb)
-                       goto nomem_err;
-
-               /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
-               usb_fill_bulk_urb (urb, stv680->udev,
-                                  usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
-                                  stv680->sbuf[i].data, stv680->rawbufsize,
-                                  stv680_video_irq, stv680);
-               stv680->urb[i] = urb;
-               err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-               if (err) {
-                       PDEBUG (0, "STV(e): urb burned down with err "
-                                  "%d in start stream %d", err, i);
-                       goto nomem_err;
-               }
-       }                       /* i STV680_NUMSBUF */
-
-       stv680->framecount = 0;
-       return 0;
-
- nomem_err:
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               usb_kill_urb(stv680->urb[i]);
-               usb_free_urb(stv680->urb[i]);
-               stv680->urb[i] = NULL;
-               kfree(stv680->sbuf[i].data);
-               stv680->sbuf[i].data = NULL;
-       }
-       /* used in irq, free only as all URBs are dead */
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               kfree(stv680->scratch[i].data);
-               stv680->scratch[i].data = NULL;
-       }
-       return -ENOMEM;
-
-}
-
-static int stv680_stop_stream (struct usb_stv *stv680)
-{
-       int i;
-
-       if (!stv680->streaming || !stv680->udev)
-               return 1;
-
-       stv680->streaming = 0;
-
-       for (i = 0; i < STV680_NUMSBUF; i++)
-               if (stv680->urb[i]) {
-                       usb_kill_urb (stv680->urb[i]);
-                       usb_free_urb (stv680->urb[i]);
-                       stv680->urb[i] = NULL;
-                       kfree(stv680->sbuf[i].data);
-               }
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               kfree(stv680->scratch[i].data);
-               stv680->scratch[i].data = NULL;
-       }
-
-       return 0;
-}
-
-static int stv680_set_size (struct usb_stv *stv680, int width, int height)
-{
-       int wasstreaming = stv680->streaming;
-
-       /* Check to see if we need to change */
-       if ((stv680->vwidth == width) && (stv680->vheight == height))
-               return 0;
-
-       PDEBUG (1, "STV(i): size request for %i x %i", width, height);
-       /* Check for a valid mode */
-       if ((!width || !height) || ((width & 1) || (height & 1))) {
-               PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-               return 1;
-       }
-
-       if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
-               width = stv680->maxwidth / 2;
-               height = stv680->maxheight / 2;
-       } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
-               width = 160;
-               height = 120;
-       } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
-               width = 176;
-               height = 144;
-       } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
-               width = 320;
-               height = 240;
-       } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
-               width = 352;
-               height = 288;
-       } else {
-               PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-               return 1;
-       }
-
-       /* Stop a current stream and start it again at the new size */
-       if (wasstreaming)
-               stv680_stop_stream (stv680);
-       stv680->vwidth = width;
-       stv680->vheight = height;
-       PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
-       if (wasstreaming)
-               stv680_start_stream (stv680);
-
-       return 0;
-}
-
-/**********************************************************************
- * Video Decoding
- **********************************************************************/
-
-/*******  routines from the pencam program; hey, they work!  ********/
-
-/*
- * STV0680 Vision Camera Chipset Driver
- * Copyright (C) 2000 Adam Harrison <adam@antispin.org>
-*/
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define AD(x, y, w) (((y)*(w)+(x))*3)
-
-static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
-{
-       int x, y, i;
-       int w = stv680->cwidth;
-       int vw = stv680->cwidth, vh = stv680->cheight;
-       unsigned int p = 0;
-       int colour = 0, bayer = 0;
-       unsigned char *raw = buffer->data;
-       struct stv680_frame *frame = &stv680->frame[stv680->curframe];
-       unsigned char *output = frame->data;
-       unsigned char *temp = frame->data;
-       int offset = buffer->offset;
-
-       if (frame->curpix == 0) {
-               if (frame->grabstate == FRAME_READY) {
-                       frame->grabstate = FRAME_GRABBING;
-               }
-       }
-       if (offset != frame->curpix) {  /* Regard frame as lost :( */
-               frame->curpix = 0;
-               stv680->error++;
-               return;
-       }
-
-       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
-               vw = 320;
-               vh = 240;
-       }
-       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
-               vw = 352;
-               vh = 288;
-       }
-
-       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
-
-       for (y = 0; y < vh; y++) {
-               for (x = 0; x < vw; x++) {
-                       if (x & 1)
-                               p = *(raw + y * w + (x >> 1));
-                       else
-                               p = *(raw + y * w + (x >> 1) + (w >> 1));
-
-                       if (y & 1)
-                               bayer = 2;
-                       else
-                               bayer = 0;
-                       if (x & 1)
-                               bayer++;
-
-                       switch (bayer) {
-                       case 0:
-                       case 3:
-                               colour = 1;
-                               break;
-                       case 1:
-                               colour = 0;
-                               break;
-                       case 2:
-                               colour = 2;
-                               break;
-                       }
-                       i = (y * vw + x) * 3;
-                       *(output + i + colour) = (unsigned char) p;
-               }               /* for x */
-
-       }                       /* for y */
-
-       /****** gamma correction plus hardcoded white balance */
-       /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
-          Correction values red[], green[], blue[], are generated by
-          (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
-          White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
-          converted to unsigned char. Values are in stv680.h  */
-
-       for (y = 0; y < vh; y++) {
-               for (x = 0; x < vw; x++) {
-                       i = (y * vw + x) * 3;
-                       *(output + i) = red[*(output + i)];
-                       *(output + i + 1) = green[*(output + i + 1)];
-                       *(output + i + 2) = blue[*(output + i + 2)];
-               }
-       }
-
-       /******  bayer demosaic  ******/
-       for (y = 1; y < (vh - 1); y++) {
-               for (x = 1; x < (vw - 1); x++) {        /* work out pixel type */
-                       if (y & 1)
-                               bayer = 0;
-                       else
-                               bayer = 2;
-                       if (!(x & 1))
-                               bayer++;
-
-                       switch (bayer) {
-                       case 0: /* green. blue lr, red tb */
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
-                               break;
-
-                       case 1: /* blue. green lrtb, red diagonals */
-                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
-                               break;
-
-                       case 2: /* red. green lrtb, blue diagonals */
-                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
-                               break;
-
-                       case 3: /* green. red lr, blue tb */
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
-                               break;
-                       }       /* switch */
-               }               /* for x */
-       }                       /* for y  - end demosaic  */
-
-       /* fix top and bottom row, left and right side */
-       i = vw * 3;
-       memcpy (output, (output + i), i);
-       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
-       for (y = 0; y < vh; y++) {
-               i = y * vw * 3;
-               memcpy ((output + i), (output + i + 3), 3);
-               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
-       }
-
-       /*  process all raw data, then trim to size if necessary */
-       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
-               i = 0;
-               for (y = 0; y < vh; y++) {
-                       if (!(y & 1)) {
-                               for (x = 0; x < vw; x++) {
-                                       p = (y * vw + x) * 3;
-                                       if (!(x & 1)) {
-                                               *(output + i) = *(output + p);
-                                               *(output + i + 1) = *(output + p + 1);
-                                               *(output + i + 2) = *(output + p + 2);
-                                               i += 3;
-                                       }
-                               }  /* for x */
-                       }
-               }  /* for y */
-       }
-       /* reset to proper width */
-       if ((stv680->vwidth == 160)) {
-               vw = 160;
-               vh = 120;
-       }
-       if ((stv680->vwidth == 176)) {
-               vw = 176;
-               vh = 144;
-       }
-
-       /* output is RGB; some programs want BGR  */
-       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
-       /* swapRGB_on=-1, never swap */
-       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
-               for (y = 0; y < vh; y++) {
-                       for (x = 0; x < vw; x++) {
-                               i = (y * vw + x) * 3;
-                               *(temp) = *(output + i);
-                               *(output + i) = *(output + i + 2);
-                               *(output + i + 2) = *(temp);
-                       }
-               }
-       }
-       /* brightness */
-       if (stv680->chgbright == 1) {
-               if (stv680->brightness >= 32767) {
-                       p = (stv680->brightness - 32767) / 256;
-                       for (x = 0; x < (vw * vh * 3); x++) {
-                               if ((*(output + x) + (unsigned char) p) > 255)
-                                       *(output + x) = 255;
-                               else
-                                       *(output + x) += (unsigned char) p;
-                       }       /* for */
-               } else {
-                       p = (32767 - stv680->brightness) / 256;
-                       for (x = 0; x < (vw * vh * 3); x++) {
-                               if ((unsigned char) p > *(output + x))
-                                       *(output + x) = 0;
-                               else
-                                       *(output + x) -= (unsigned char) p;
-                       }       /* for */
-               }               /* else */
-       }
-       /* if */
-       frame->curpix = 0;
-       frame->curlinepix = 0;
-       frame->grabstate = FRAME_DONE;
-       stv680->framecount++;
-       stv680->readcount++;
-       if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
-               stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
-       }
-
-}                              /* bayer_unshuffle */
-
-/*******  end routines from the pencam program  *********/
-
-static int stv680_newframe (struct usb_stv *stv680, int framenr)
-{
-       int errors = 0;
-
-       while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
-               if (!stv680->frame[framenr].curpix) {
-                       errors++;
-               }
-               wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
-
-               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-                       stv680->nullpackets = 0;
-                       PDEBUG (2, "STV(i): too many null length packets, restarting capture");
-                       stv680_stop_stream (stv680);
-                       stv680_start_stream (stv680);
-               } else {
-                       if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
-                               stv680->frame[framenr].grabstate = FRAME_ERROR;
-                               PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
-                               return -EIO;
-                       }
-                       stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
-
-                       bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
-
-                       stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
-                       stv680->scratch_use++;
-                       if (stv680->scratch_use >= STV680_NUMSCRATCH)
-                               stv680->scratch_use = 0;
-                       if (errors > STV680_MAX_ERRORS) {
-                               errors = 0;
-                               PDEBUG (2, "STV(i): too many errors, restarting capture");
-                               stv680_stop_stream (stv680);
-                               stv680_start_stream (stv680);
-                       }
-               }               /* else */
-       }                       /* while */
-       return 0;
-}
-
-/*********************************************************************
- * Video4Linux
- *********************************************************************/
-
-static int stv_open(struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       int err = 0;
-
-       /* we are called with the BKL held */
-       lock_kernel();
-       stv680->user = 1;
-       err = stv_init (stv680);        /* main initialization routine for camera */
-
-       if (err >= 0) {
-               stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
-               if (!stv680->fbuf) {
-                       PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
-                       err = -ENOMEM;
-               }
-               file->private_data = dev;
-       }
-       if (err)
-               stv680->user = 0;
-       unlock_kernel();
-
-       return err;
-}
-
-static int stv_close(struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       int i;
-
-       for (i = 0; i < STV680_NUMFRAMES; i++)
-               stv680->frame[i].grabstate = FRAME_UNUSED;
-       if (stv680->streaming)
-               stv680_stop_stream (stv680);
-
-       if ((i = stv_stop_video (stv680)) < 0)
-               PDEBUG (1, "STV(e): stop_video failed in stv_close");
-
-       rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
-       stv680->user = 0;
-
-       if (stv680->removed) {
-               kfree(stv680);
-               stv680 = NULL;
-               PDEBUG (0, "STV(i): device unregistered");
-       }
-       file->private_data = NULL;
-       return 0;
-}
-
-static long stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(vdev);
-
-       if (!stv680->udev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:{
-                       struct video_capability *b = arg;
-
-                       strcpy (b->name, stv680->camera_name);
-                       b->type = VID_TYPE_CAPTURE;
-                       b->channels = 1;
-                       b->audios = 0;
-                       b->maxwidth = stv680->maxwidth;
-                       b->maxheight = stv680->maxheight;
-                       b->minwidth = stv680->maxwidth / 2;
-                       b->minheight = stv680->maxheight / 2;
-                       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, "STV 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;
-
-                       stv680_get_pict (stv680, p);
-                       return 0;
-               }
-       case VIDIOCSPICT:{
-                       struct video_picture *p = arg;
-
-                       if (stv680_set_pict (stv680, p))
-                               return -EINVAL;
-                       return 0;
-               }
-       case VIDIOCSWIN:{
-                       struct video_window *vw = arg;
-
-                       if (vw->flags)
-                               return -EINVAL;
-                       if (vw->clipcount)
-                               return -EINVAL;
-                       if (vw->width != stv680->vwidth) {
-                               if (stv680_set_size (stv680, vw->width, vw->height)) {
-                                       PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
-                                       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 = stv680->vwidth;
-                       vw->height = stv680->vheight;
-                       return 0;
-               }
-       case VIDIOCGMBUF:{
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset (vm, 0, sizeof (*vm));
-                       vm->size = STV680_NUMFRAMES * stv680->maxframesize;
-                       vm->frames = STV680_NUMFRAMES;
-                       for (i = 0; i < STV680_NUMFRAMES; i++)
-                               vm->offsets[i] = stv680->maxframesize * i;
-                       return 0;
-               }
-       case VIDIOCMCAPTURE:{
-                       struct video_mmap *vm = arg;
-
-                       if (vm->format != STV_VIDEO_PALETTE) {
-                               PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
-                                       vm->format, STV_VIDEO_PALETTE);
-                               if ((vm->format == 3) && (swapRGB_on == 0))  {
-                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
-                                       /* this may fix those apps (e.g., xawtv) that want BGR */
-                                       swapRGB = 1;
-                               }
-                               return -EINVAL;
-                       }
-                       if (vm->frame >= STV680_NUMFRAMES) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
-                               return -EINVAL;
-                       }
-                       if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
-                           || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
-                                       stv680->frame[vm->frame].grabstate);
-                               return -EBUSY;
-                       }
-                       /* Is this according to the v4l spec??? */
-                       if (stv680->vwidth != vm->width) {
-                               if (stv680_set_size (stv680, vm->width, vm->height)) {
-                                       PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
-                                       return -EINVAL;
-                               }
-                       }
-                       stv680->frame[vm->frame].grabstate = FRAME_READY;
-
-                       if (!stv680->streaming)
-                               stv680_start_stream (stv680);
-
-                       return 0;
-               }
-       case VIDIOCSYNC:{
-                       int *frame = arg;
-                       int ret = 0;
-
-                       if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
-                               PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
-                               return -EINVAL;
-                       }
-                       ret = stv680_newframe (stv680, *frame);
-                       stv680->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:
-               {
-                       PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
-                       return -EINVAL;
-               }
-       case VIDIOCSFBUF:
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-       default:
-               return -ENOIOCTLCMD;
-       }                       /* end switch */
-
-       return 0;
-}
-
-static long stv680_ioctl(struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(file, cmd, arg, stv680_do_ioctl);
-}
-
-static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       mutex_lock(&stv680->lock);
-
-       if (stv680->udev == NULL) {
-               mutex_unlock(&stv680->lock);
-               return -EIO;
-       }
-       if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
-                   & ~(PAGE_SIZE - 1))) {
-               mutex_unlock(&stv680->lock);
-               return -EINVAL;
-       }
-       pos = (unsigned long) stv680->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&stv680->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       mutex_unlock(&stv680->lock);
-
-       return 0;
-}
-
-static ssize_t stv680_read (struct file *file, char __user *buf,
-                       size_t count, loff_t *ppos)
-{
-       struct video_device *dev = file->private_data;
-       unsigned long int realcount = count;
-       int ret = 0;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       unsigned long int i;
-
-       if (STV680_NUMFRAMES != 2) {
-               PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
-               return -1;
-       }
-       if (stv680->udev == NULL)
-               return -EIO;
-       if (realcount > (stv680->vwidth * stv680->vheight * 3))
-               realcount = stv680->vwidth * stv680->vheight * 3;
-
-       /* Shouldn't happen: */
-       if (stv680->frame[0].grabstate == FRAME_GRABBING) {
-               PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
-               return -EBUSY;
-       }
-       stv680->frame[0].grabstate = FRAME_READY;
-       stv680->frame[1].grabstate = FRAME_UNUSED;
-       stv680->curframe = 0;
-
-       if (!stv680->streaming)
-               stv680_start_stream (stv680);
-
-       if (!stv680->streaming) {
-               ret = stv680_newframe (stv680, 0);      /* ret should = 0 */
-       }
-
-       ret = stv680_newframe (stv680, 0);
-
-       if (!ret) {
-               if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
-                       PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
-                       return -EFAULT;
-               }
-       } else {
-               realcount = ret;
-       }
-       stv680->frame[0].grabstate = FRAME_UNUSED;
-       return realcount;
-}                              /* stv680_read */
-
-static const struct v4l2_file_operations stv680_fops = {
-       .owner =        THIS_MODULE,
-       .open =         stv_open,
-       .release =      stv_close,
-       .read =         stv680_read,
-       .mmap =         stv680_mmap,
-       .ioctl =        stv680_ioctl,
-};
-static struct video_device stv680_template = {
-       .name =         "STV0680 USB camera",
-       .fops =         &stv680_fops,
-       .release =      video_device_release,
-};
-
-static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_host_interface *interface;
-       struct usb_stv *stv680 = NULL;
-       char *camera_name = NULL;
-       int retval = 0;
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1) {
-               PDEBUG (0, "STV(e): Number of Configurations != 1");
-               return -ENODEV;
-       }
-
-       interface = &intf->altsetting[0];
-       /* Is it a STV680? */
-       if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
-           (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
-               camera_name = "STV0680";
-               PDEBUG (0, "STV(i): STV0680 camera found.");
-       } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
-                  (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
-               camera_name = "Creative WebCam Go Mini";
-               PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
-       } else {
-               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
-               PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
-               retval = -ENODEV;
-               goto error;
-       }
-       /* We found one */
-       if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
-               PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
-               retval = -ENOMEM;
-               goto error;
-       }
-
-       stv680->udev = dev;
-       stv680->camera_name = camera_name;
-
-       stv680->vdev = video_device_alloc();
-       if (!stv680->vdev) {
-               retval = -ENOMEM;
-               goto error;
-       }
-       memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
-       stv680->vdev->parent = &intf->dev;
-       video_set_drvdata(stv680->vdev, stv680);
-
-       memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
-       init_waitqueue_head (&stv680->wq);
-       mutex_init (&stv680->lock);
-       wmb ();
-
-       if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
-               PDEBUG (0, "STV(e): video_register_device failed");
-               retval = -EIO;
-               goto error_vdev;
-       }
-       PDEBUG(0, "STV(i): registered new video device: %s",
-               video_device_node_name(stv680->vdev));
-
-       usb_set_intfdata (intf, stv680);
-       retval = stv680_create_sysfs_files(stv680->vdev);
-       if (retval)
-               goto error_unreg;
-       return 0;
-
-error_unreg:
-       video_unregister_device(stv680->vdev);
-error_vdev:
-       video_device_release(stv680->vdev);
-error:
-       kfree(stv680);
-       return retval;
-}
-
-static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
-{
-       int i;
-
-       stv680->udev = NULL;
-       stv680->frame[0].grabstate = FRAME_ERROR;
-       stv680->frame[1].grabstate = FRAME_ERROR;
-       stv680->streaming = 0;
-
-       wake_up_interruptible (&stv680->wq);
-
-       for (i = 0; i < STV680_NUMSBUF; i++)
-               if (stv680->urb[i]) {
-                       usb_kill_urb (stv680->urb[i]);
-                       usb_free_urb (stv680->urb[i]);
-                       stv680->urb[i] = NULL;
-                       kfree(stv680->sbuf[i].data);
-               }
-       for (i = 0; i < STV680_NUMSCRATCH; i++)
-               kfree(stv680->scratch[i].data);
-       PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
-
-       /* Free the memory */
-       kfree(stv680);
-}
-
-static void stv680_disconnect (struct usb_interface *intf)
-{
-       struct usb_stv *stv680 = usb_get_intfdata (intf);
-
-       usb_set_intfdata (intf, NULL);
-
-       if (stv680) {
-               /* We don't want people trying to open up the device */
-               if (stv680->vdev) {
-                       stv680_remove_sysfs_files(stv680->vdev);
-                       video_unregister_device(stv680->vdev);
-                       stv680->vdev = NULL;
-               }
-               if (!stv680->user) {
-                       usb_stv680_remove_disconnected (stv680);
-               } else {
-                       stv680->removed = 1;
-               }
-       }
-}
-
-static struct usb_driver stv680_driver = {
-       .name =         "stv680",
-       .probe =        stv680_probe,
-       .disconnect =   stv680_disconnect,
-       .id_table =     device_table
-};
-
-/********************************************************************
- *  Module routines
- ********************************************************************/
-
-static int __init usb_stv680_init (void)
-{
-       if (usb_register (&stv680_driver) < 0) {
-               PDEBUG (0, "STV(e): Could not setup STV0680 driver");
-               return -1;
-       }
-       PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
-
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-              DRIVER_DESC "\n");
-       return 0;
-}
-
-static void __exit usb_stv680_exit (void)
-{
-       usb_deregister (&stv680_driver);
-       PDEBUG (0, "STV(i): driver deregistered");
-}
-
-module_init (usb_stv680_init);
-module_exit (usb_stv680_exit);
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h
deleted file mode 100644 (file)
index a08f1b0..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
- *
- *  Filename: stv680.h
- *
- *  Description:
- *     This is a USB driver for STV0680 based usb video cameras.
- *
- *  This program is free software; 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.
- *
- ****************************************************************************/
-
-/* size of usb transfers */
-#define STV680_PACKETSIZE      4096
-
-/* number of queued bulk transfers to use, may have problems if > 1 */
-#define STV680_NUMSBUF         1
-
-/* number of frames supported by the v4l part */
-#define STV680_NUMFRAMES       2
-
-/* scratch buffers for passing data to the decoders: 2 or 4 are good */
-#define STV680_NUMSCRATCH      2
-
-/* number of nul sized packets to receive before kicking the camera */
-#define STV680_MAX_NULLPACKETS 200
-
-/* number of decoding errors before kicking the camera */
-#define STV680_MAX_ERRORS      100
-
-#define USB_PENCAM_VENDOR_ID   0x0553
-#define USB_PENCAM_PRODUCT_ID  0x0202
-
-#define USB_CREATIVEGOMINI_VENDOR_ID   0x041e
-#define USB_CREATIVEGOMINI_PRODUCT_ID  0x4007
-
-#define PENCAM_TIMEOUT          1000
-/* fmt 4 */
-#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
-
-static struct usb_device_id device_table[] = {
-       {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
-       {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
-       {}
-};
-MODULE_DEVICE_TABLE (usb, device_table);
-
-struct stv680_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 {
-       BUFFER_UNUSED,
-       BUFFER_READY,
-       BUFFER_BUSY,
-       BUFFER_DONE,
-};
-
-/* raw camera data <- sbuf (urb transfer buf) */
-struct stv680_scratch {
-       unsigned char *data;
-       volatile int state;
-       int offset;
-       int length;
-};
-
-/* processed data for display ends up here, after bayer */
-struct stv680_frame {
-       unsigned char *data;    /* Frame buffer */
-       volatile int grabstate; /* State of grabbing */
-       unsigned char *curline;
-       int curlinepix;
-       int curpix;
-};
-
-/* this is almost the video structure uvd_t, with extra parameters for stv */
-struct usb_stv {
-       struct video_device *vdev;
-
-       struct usb_device *udev;
-
-       unsigned char bulk_in_endpointAddr;     /* __u8  the address of the bulk in endpoint */
-       char *camera_name;
-
-       unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
-       int SupportedModes;
-       int CIF;
-       int VGA;
-       int QVGA;
-       int cwidth;             /* camera width */
-       int cheight;            /* camera height */
-       int maxwidth;           /* max video width */
-       int maxheight;          /* max video height */
-       int vwidth;             /* current width for video window */
-       int vheight;            /* current height for video window */
-       unsigned long int rawbufsize;
-       unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
-
-       int origGain;
-       int origMode;           /* original camera mode */
-
-       struct mutex lock;      /* to lock the structure */
-       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[STV680_NUMSBUF];        /* # of queued bulk transfers */
-       int curframe;           /* Current receiving frame */
-       struct stv680_frame frame[STV680_NUMFRAMES];    /* # frames supported by v4l part */
-       int readcount;
-       int framecount;
-       int error;
-       int dropped;
-       int scratch_next;
-       int scratch_use;
-       int scratch_overflow;
-       struct stv680_scratch scratch[STV680_NUMSCRATCH];       /* for decoders */
-       struct stv680_sbuf sbuf[STV680_NUMSBUF];
-
-       unsigned int brightness;
-       unsigned int chgbright;
-       unsigned int whiteness;
-       unsigned int colour;
-       unsigned int contrast;
-       unsigned int hue;
-       unsigned int palette;
-       unsigned int depth;     /* rgb24 in bits */
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int nullpackets;
-};
-
-
-static const unsigned char red[256] = {
-       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
-       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42,
-       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69,
-       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87,
-       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101,
-       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
-       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124,
-       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134,
-       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143,
-       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151,
-       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
-       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166,
-       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173,
-       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179,
-       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186,
-       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192,
-       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197,
-       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204,
-       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209,
-       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
-       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219,
-       220, 220, 221, 221
-};
-
-static const unsigned char green[256] = {
-       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-       245, 245, 246, 246
-};
-
-static const unsigned char blue[256] = {
-       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51,
-       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84,
-       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106,
-       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124,
-       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138,
-       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151,
-       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163,
-       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174,
-       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184,
-       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194,
-       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203,
-       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212,
-       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220,
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235,
-       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242,
-       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249,
-       249, 250, 250, 251, 251, 253, 253, 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,
-       255, 255, 255, 255
-};
index 256cc558ba13478d68c8f1801be6cb13e5b4b15b..4555f4a5f4c84b94f532d6993a5d0591e4569ae9 100644 (file)
@@ -227,12 +227,11 @@ static int firmware_download(struct usb_device *udev)
 
        fwlength = fw->size;
 
-       fwbuf = kzalloc(fwlength, GFP_KERNEL);
+       fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL);
        if (!fwbuf) {
                ret = -ENOMEM;
                goto out;
        }
-       memcpy(fwbuf, fw->data, fwlength);
 
        max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
        log("\t\t download size : %d", (int)max_packet_size);
index 445dc93413e3ae32ffd7ab3654b3687b3ba600ce..a727962781a363bf97309734d18becf69b0e23aa 100644 (file)
@@ -768,7 +768,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
 
        mf->width       = priv->scale->width;
        mf->height      = priv->scale->height;
-       mf->code        = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+       mf->code        = V4L2_MBUS_FMT_UYVY8_2X8;
        mf->colorspace  = V4L2_COLORSPACE_JPEG;
        mf->field       = V4L2_FIELD_INTERLACED_BT;
 
@@ -797,7 +797,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
        /*
         * check color format
         */
-       if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE)
+       if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
                return -EINVAL;
 
        mf->colorspace = V4L2_COLORSPACE_JPEG;
@@ -824,7 +824,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
                return -EINVAL;
        }
 
-       mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+       mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
        mf->colorspace = V4L2_COLORSPACE_JPEG;
 
        /*
@@ -909,7 +909,7 @@ static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
        if (index)
                return -EINVAL;
 
-       *code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+       *code = V4L2_MBUS_FMT_UYVY8_2X8;
        return 0;
 }
 
index adb1c044ad7dedcbaf4687e5c934fa196e822886..d6e16959f78bba0668fa5330c5bb136fe90f127b 100644 (file)
@@ -37,17 +37,3 @@ config USB_KONICAWC
          To compile this driver as a module, choose M here: the
          module will be called konicawc.
 
-config USB_QUICKCAM_MESSENGER
-       tristate "USB Logitech Quickcam Messenger (DEPRECATED)"
-       depends on VIDEO_V4L1
-       select VIDEO_USBVIDEO
-       ---help---
-         This driver is DEPRECATED please use the gspca stv06xx module
-         instead.
-
-         Say Y or M here to enable support for the USB Logitech Quickcam
-         Messenger webcam.
-
-         To compile this driver as a module, choose M here: the
-         module will be called quickcam_messenger.
-
index 4a1b144bee4df9f449bea41024f43f1a36a5b320..bb52eb8dc2f9c1b501484c117772ae5ed511017f 100644 (file)
@@ -2,4 +2,3 @@ obj-$(CONFIG_VIDEO_USBVIDEO)    += usbvideo.o
 obj-$(CONFIG_USB_IBMCAM)        += ibmcam.o ultracam.o
 obj-$(CONFIG_USB_KONICAWC)      += konicawc.o
 obj-$(CONFIG_USB_VICAM)         += vicam.o
-obj-$(CONFIG_USB_QUICKCAM_MESSENGER)   += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
deleted file mode 100644 (file)
index fbd665f..0000000
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Driver for Logitech Quickcam Messenger usb video camera
- * Copyright (C) Jaya Kumar
- *
- * This work was sponsored by CIS(M) Sdn Bhd.
- * History:
- * 05/08/2006 - Jaya Kumar
- * I wrote this based on the konicawc by Simon Evans.
- * -
- * Full credit for reverse engineering and creating an initial
- * working linux driver for the VV6422 goes to the qce-ga project by
- * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
- * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
- * others.
- * ---
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb/input.h>
-#include <linux/slab.h>
-
-#include "usbvideo.h"
-#include "quickcam_messenger.h"
-
-/*
- * Version Information
- */
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
-       if (n <= debug) {        \
-               printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
-       }
-#else
-#define DEBUG(n, arg...)
-static const int debug;
-#endif
-
-#define DRIVER_VERSION "v0.01"
-#define DRIVER_DESC "Logitech Quickcam Messenger USB"
-
-#define USB_LOGITECH_VENDOR_ID 0x046D
-#define USB_QCM_PRODUCT_ID     0x08F0
-
-#define MAX_CAMERAS    1
-
-#define MAX_COLOUR     32768
-#define MAX_HUE                32768
-#define MAX_BRIGHTNESS 32768
-#define MAX_CONTRAST   32768
-#define MAX_WHITENESS  32768
-
-static int size = SIZE_320X240;
-static int colour = MAX_COLOUR;
-static int hue = MAX_HUE;
-static int brightness =        MAX_BRIGHTNESS;
-static int contrast =  MAX_CONTRAST;
-static int whiteness = MAX_WHITENESS;
-
-static struct usbvideo *cams;
-
-static struct usb_device_id qcm_table [] = {
-       { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
-       { }
-};
-MODULE_DEVICE_TABLE(usb, qcm_table);
-
-#ifdef CONFIG_INPUT
-static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
-{
-       struct input_dev *input_dev;
-       int error;
-
-       usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
-       strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
-       cam->input = input_dev = input_allocate_device();
-       if (!input_dev) {
-               dev_warn(&dev->dev, "insufficient mem for cam input device\n");
-               return;
-       }
-
-       input_dev->name = "QCM button";
-       input_dev->phys = cam->input_physname;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->dev.parent = &dev->dev;
-
-       input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
-
-       error = input_register_device(cam->input);
-       if (error) {
-               dev_warn(&dev->dev,
-                        "Failed to register camera's input device, err: %d\n",
-                        error);
-               input_free_device(cam->input);
-               cam->input = NULL;
-       }
-}
-
-static void qcm_unregister_input(struct qcm *cam)
-{
-       if (cam->input) {
-               input_unregister_device(cam->input);
-               cam->input = NULL;
-       }
-}
-
-static void qcm_report_buttonstat(struct qcm *cam)
-{
-       if (cam->input) {
-               input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
-               input_sync(cam->input);
-       }
-}
-
-static void qcm_int_irq(struct urb *urb)
-{
-       int ret;
-       struct uvd *uvd = urb->context;
-       struct qcm *cam;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-
-       if (!uvd->streaming)
-               return;
-
-       uvd->stats.urb_count++;
-
-       if (urb->status < 0)
-               uvd->stats.iso_err_count++;
-       else {
-               if (urb->actual_length > 0 ) {
-                       cam = (struct qcm *) uvd->user_data;
-                       if (cam->button_sts_buf == 0x88)
-                               cam->button_sts = 0x0;
-                       else if (cam->button_sts_buf == 0x80)
-                               cam->button_sts = 0x1;
-                       qcm_report_buttonstat(cam);
-               }
-       }
-
-       ret = usb_submit_urb(urb, GFP_ATOMIC);
-       if (ret < 0)
-               err("usb_submit_urb error (%d)", ret);
-}
-
-static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
-{
-       int errflag;
-       usb_fill_int_urb(cam->button_urb, uvd->dev,
-                       usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
-                       &cam->button_sts_buf,
-                       1,
-                       qcm_int_irq,
-                       uvd, 16);
-
-       errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
-       if (errflag)
-               err ("usb_submit_int ret %d", errflag);
-       return errflag;
-}
-
-static void qcm_stop_int_data(struct qcm *cam)
-{
-       usb_kill_urb(cam->button_urb);
-}
-
-static int qcm_alloc_int_urb(struct qcm *cam)
-{
-       cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
-
-       if (!cam->button_urb)
-               return -ENOMEM;
-
-       return 0;
-}
-
-static void qcm_free_int(struct qcm *cam)
-{
-       usb_free_urb(cam->button_urb);
-}
-#endif /* CONFIG_INPUT */
-
-static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
-{
-       int ret;
-
-       /* we'll wait up to 3 slices but no more */
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-               reg, 0, &val, 1, 3*HZ);
-       return ret;
-}
-
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
-{
-       int ret;
-
-       /* we'll wait up to 3 slices but no more */
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-               reg, 0, &val, 2, 3*HZ);
-       return ret;
-}
-
-static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
-                                                       __le16 *val)
-{
-       int ret;
-
-       /* we'll wait up to 3 slices but no more */
-       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-               0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
-               reg, 0, val, 2, 3*HZ);
-       return ret;
-}
-
-static int qcm_camera_on(struct uvd *uvd)
-{
-       int ret;
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
-       return 0;
-}
-
-static int qcm_camera_off(struct uvd *uvd)
-{
-       int ret;
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
-       return 0;
-}
-
-static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
-{
-       unsigned int segment, valsat;
-       signed int   h = (signed int) hue;
-       unsigned int s = (sat - 32768) * 2;     /* rescale */
-       unsigned int v = val;
-       unsigned int p;
-
-       /*
-       the registers controlling gain are 8 bit of which
-       we affect only the last 4 bits with our gain.
-       we know that if saturation is 0, (unsaturated) then
-       we're grayscale (center axis of the colour cone) so
-       we set rgb=value. we use a formula obtained from
-       wikipedia to map the cone to the RGB plane. it's
-       as follows for the human value case of h=0..360,
-       s=0..1, v=0..1
-       h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
-       q = v(1 - f*s) , t = v(1 - (1-f)s)
-       h_i==0 => r=v , g=t, b=p
-       h_i==1 => r=q , g=v, b=p
-       h_i==2 => r=p , g=v, b=t
-       h_i==3 => r=p , g=q, b=v
-       h_i==4 => r=t , g=p, b=v
-       h_i==5 => r=v , g=p, b=q
-       the bottom side (the point) and the stuff just up
-       of that is black so we simplify those two cases.
-       */
-       if (sat < 32768) {
-               /* anything less than this is unsaturated */
-               *r = val;
-               *g = val;
-               *b = val;
-               return;
-       }
-       if (val <= (0xFFFF/8)) {
-               /* anything less than this is black */
-               *r = 0;
-               *g = 0;
-               *b = 0;
-               return;
-       }
-
-       /* the rest of this code is copying tukkat's
-       implementation of the hsv2rgb conversion as taken
-       from qc-usb-messenger code. the 10923 is 0xFFFF/6
-       to divide the cone into 6 sectors.  */
-
-       segment = (h + 10923) & 0xFFFF;
-       segment = segment*3 >> 16;              /* 0..2: 0=R, 1=G, 2=B */
-       hue -= segment * 21845;                 /* -10923..10923 */
-       h = hue;
-       h *= 3;
-       valsat = v*s >> 16;                     /* 0..65534 */
-       p = v - valsat;
-       if (h >= 0) {
-               unsigned int t = v - (valsat * (32769 - h) >> 15);
-               switch (segment) {
-               case 0: /* R-> */
-                       *r = v;
-                       *g = t;
-                       *b = p;
-                       break;
-               case 1: /* G-> */
-                       *r = p;
-                       *g = v;
-                       *b = t;
-                       break;
-               case 2: /* B-> */
-                       *r = t;
-                       *g = p;
-                       *b = v;
-                       break;
-               }
-       } else {
-               unsigned int q = v - (valsat * (32769 + h) >> 15);
-               switch (segment) {
-               case 0: /* ->R */
-                       *r = v;
-                       *g = p;
-                       *b = q;
-                       break;
-               case 1: /* ->G */
-                       *r = q;
-                       *g = v;
-                       *b = p;
-                       break;
-               case 2: /* ->B */
-                       *r = p;
-                       *g = q;
-                       *b = v;
-                       break;
-               }
-       }
-}
-
-static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
-       u16 saturation, u16 value)
-{
-       int ret;
-       u16 r=0,g=0,b=0;
-
-       /* this code is based on qc-usb-messenger */
-       qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
-
-       r >>= 12;
-       g >>= 12;
-       b >>= 12;
-
-       /* min val is 8 */
-       r = max((u16) 8, r);
-       g = max((u16) 8, g);
-       b = max((u16) 8, b);
-
-       r |= 0x30;
-       g |= 0x30;
-       b |= 0x30;
-
-       /* set the r,g,b gain registers */
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
-
-       /* doing as qc-usb did */
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
-       return 0;
-}
-
-static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
-{
-       int ret;
-       int formedval;
-
-       /* calculation was from qc-usb-messenger driver */
-       formedval = ( exposure >> 12 );
-
-       /* max value for formedval is 14 */
-       formedval = min(formedval, 14);
-
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev,
-                       0x143A, 0xF0 | formedval));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-       return 0;
-}
-
-static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
-                                       int hue, int colour)
-{
-       int ret;
-       /* brightness is exposure, contrast is gain, colour is saturation */
-       CHECK_RET(ret,
-               qcm_sensor_set_exposure(uvd, brightness));
-       CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
-
-       return 0;
-}
-
-static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
-{
-       int ret;
-
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
-       return 0;
-}
-
-static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
-{
-       int ret;
-       /* some rescaling as done by the qc-usb-messenger code */
-       if (whiteness > 0xC000)
-               whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
-
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
-                               (whiteness >> 8) & 0xFF));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
-                               (whiteness >> 16) & 0x03));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
-       return 0;
-}
-
-static int qcm_sensor_init(struct uvd *uvd)
-{
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-       int ret;
-       int i;
-
-       for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
-               CHECK_RET(ret, qcm_stv_setb(uvd->dev,
-                                       regval_table[i].reg,
-                                       regval_table[i].val));
-       }
-
-       CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
-                               cpu_to_le16(ISOC_PACKET_SIZE)));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143f, 0x01));
-
-       CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
-
-       CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
-       CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
-                       uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
-
-       CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
-       CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
-       return 0;
-}
-
-static int qcm_set_camera_size(struct uvd *uvd)
-{
-       int ret;
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-
-       CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-       cam->width = camera_sizes[cam->size].width;
-       cam->height = camera_sizes[cam->size].height;
-       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
-       return 0;
-}
-
-static int qcm_setup_on_open(struct uvd *uvd)
-{
-       int ret;
-
-       CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
-                               uvd->vpic.colour, uvd->vpic.contrast));
-       CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
-       CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
-       CHECK_RET(ret, qcm_set_camera_size(uvd));
-       CHECK_RET(ret, qcm_camera_on(uvd));
-       return 0;
-}
-
-static void qcm_adjust_picture(struct uvd *uvd)
-{
-       int ret;
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-
-       ret = qcm_camera_off(uvd);
-       if (ret) {
-               err("can't turn camera off. abandoning pic adjustment");
-               return;
-       }
-
-       /* if there's been a change in contrast, hue, or
-       colour then we need to recalculate hsv in order
-       to update gains */
-       if ((cam->contrast != uvd->vpic.contrast) ||
-               (cam->hue != uvd->vpic.hue) ||
-               (cam->colour != uvd->vpic.colour)) {
-               cam->contrast = uvd->vpic.contrast;
-               cam->hue = uvd->vpic.hue;
-               cam->colour = uvd->vpic.colour;
-               ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
-                                               cam->contrast);
-               if (ret) {
-                       err("can't set gains. abandoning pic adjustment");
-                       return;
-               }
-       }
-
-       if (cam->brightness != uvd->vpic.brightness) {
-               cam->brightness = uvd->vpic.brightness;
-               ret = qcm_sensor_set_exposure(uvd, cam->brightness);
-               if (ret) {
-                       err("can't set exposure. abandoning pic adjustment");
-                       return;
-               }
-       }
-
-       if (cam->whiteness != uvd->vpic.whiteness) {
-               cam->whiteness = uvd->vpic.whiteness;
-               qcm_sensor_set_shutter(uvd, cam->whiteness);
-               if (ret) {
-                       err("can't set shutter. abandoning pic adjustment");
-                       return;
-               }
-       }
-
-       ret = qcm_camera_on(uvd);
-       if (ret) {
-               err("can't reenable camera. pic adjustment failed");
-               return;
-       }
-}
-
-static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
-{
-       int datalen;
-       int totaldata;
-       struct framehdr {
-               __be16 id;
-               __be16 len;
-       };
-       struct framehdr *fhdr;
-
-       totaldata = 0;
-       while (framelen) {
-               fhdr = (struct framehdr *) cdata;
-               datalen = be16_to_cpu(fhdr->len);
-               framelen -= 4;
-               cdata += 4;
-
-               if ((fhdr->id) == cpu_to_be16(0x8001)) {
-                       RingQueue_Enqueue(&uvd->dp, marker, 4);
-                       totaldata += 4;
-                       continue;
-               }
-               if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
-                       RingQueue_Enqueue(&uvd->dp, cdata, datalen);
-                       totaldata += datalen;
-               }
-               framelen -= datalen;
-               cdata += datalen;
-       }
-       return totaldata;
-}
-
-static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
-{
-       int totlen;
-       int i;
-       unsigned char *cdata;
-
-       totlen=0;
-       for (i = 0; i < dataurb->number_of_packets; i++) {
-               int n = dataurb->iso_frame_desc[i].actual_length;
-               int st = dataurb->iso_frame_desc[i].status;
-
-               cdata = dataurb->transfer_buffer +
-                       dataurb->iso_frame_desc[i].offset;
-
-               if (st < 0) {
-                       dev_warn(&uvd->dev->dev,
-                                "Data error: packet=%d. len=%d. status=%d.\n",
-                                i, n, st);
-                       uvd->stats.iso_err_count++;
-                       continue;
-               }
-               if (!n)
-                       continue;
-
-               totlen += qcm_process_frame(uvd, cdata, n);
-       }
-       return totlen;
-}
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
-       int ret;
-
-       urb->dev = uvd->dev;
-       ret = usb_submit_urb(urb, GFP_ATOMIC);
-       if (ret)
-               err("usb_submit_urb error (%d)", ret);
-}
-
-static void qcm_isoc_irq(struct urb *urb)
-{
-       int len;
-       struct uvd *uvd = urb->context;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-
-       if (!uvd->streaming)
-               return;
-
-       uvd->stats.urb_count++;
-
-       if (!urb->actual_length) {
-               resubmit_urb(uvd, urb);
-               return;
-       }
-
-       len = qcm_compress_iso(uvd, urb);
-       resubmit_urb(uvd, urb);
-       uvd->stats.urb_length = len;
-       uvd->stats.data_count += len;
-       if (len)
-               RingQueue_WakeUpInterruptible(&uvd->dp);
-}
-
-static int qcm_start_data(struct uvd *uvd)
-{
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-       int i;
-       int errflag;
-       int pktsz;
-       int err;
-
-       pktsz = uvd->iso_packet_len;
-       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-               err("Camera is not operational");
-               return -EFAULT;
-       }
-
-       err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
-       if (err < 0) {
-               err("usb_set_interface error");
-               uvd->last_error = err;
-               return -EBUSY;
-       }
-
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               int j, k;
-               struct urb *urb = uvd->sbuf[i].urb;
-               urb->dev = uvd->dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = uvd->sbuf[i].data;
-               urb->complete = qcm_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
-               for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = pktsz;
-               }
-       }
-
-       uvd->streaming = 1;
-       uvd->curframe = -1;
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-               if (errflag)
-                       err ("usb_submit_isoc(%d) ret %d", i, errflag);
-       }
-
-       CHECK_RET(err, qcm_setup_input_int(cam, uvd));
-       CHECK_RET(err, qcm_camera_on(uvd));
-       return 0;
-}
-
-static void qcm_stop_data(struct uvd *uvd)
-{
-       struct qcm *cam;
-       int i, j;
-       int ret;
-
-       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-               return;
-       cam = (struct qcm *) uvd->user_data;
-
-       ret = qcm_camera_off(uvd);
-       if (ret)
-               dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n");
-
-       uvd->streaming = 0;
-
-       /* Unschedule all of the iso td's */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++)
-               usb_kill_urb(uvd->sbuf[i].urb);
-
-       qcm_stop_int_data(cam);
-
-       if (!uvd->remove_pending) {
-               /* Set packet size to 0 */
-               j = usb_set_interface(uvd->dev, uvd->iface,
-                                       uvd->ifaceAltInactive);
-               if (j < 0) {
-                       err("usb_set_interface() error %d.", j);
-                       uvd->last_error = j;
-               }
-       }
-}
-
-static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-       int x;
-       struct rgb *rgbL0;
-       struct rgb *rgbL1;
-       struct bayL0 *bayL0;
-       struct bayL1 *bayL1;
-       int hor,ver,hordel,verdel;
-       assert(frame != NULL);
-
-       switch (cam->size) {
-       case SIZE_160X120:
-               hor = 162; ver = 124; hordel = 1; verdel = 2;
-               break;
-       case SIZE_320X240:
-       default:
-               hor = 324; ver = 248; hordel = 2; verdel = 4;
-               break;
-       }
-
-       if (frame->scanstate == ScanState_Scanning) {
-               while (RingQueue_GetLength(&uvd->dp) >=
-                        4 + (hor*verdel + hordel)) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
-                               frame->curline = 0;
-                               frame->scanstate = ScanState_Lines;
-                               frame->frameState = FrameState_Grabbing;
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
-                       /*
-                       * if we're starting, we need to discard the first
-                       * 4 lines of y bayer data
-                       * and the first 2 gr elements of x bayer data
-                       */
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
-                                                       (hor*verdel + hordel));
-                               break;
-                       }
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-       }
-
-       if (frame->scanstate == ScanState_Scanning)
-               return;
-
-       /* now we can start processing bayer data so long as we have at least
-       * 2 lines worth of data. this is the simplest demosaicing method that
-       * I could think of. I use each 2x2 bayer element without interpolation
-       * to generate 4 rgb pixels.
-       */
-       while ( frame->curline < cam->height &&
-               (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
-               /* get 2 lines of bayer for demosaicing
-                * into 2 lines of RGB */
-               RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
-               bayL0 = (struct bayL0 *) cam->scratch;
-               bayL1 = (struct bayL1 *) (cam->scratch + hor);
-               /* frame->curline is the rgb y line */
-               rgbL0 = (struct rgb *)
-                               ( frame->data + (cam->width*3*frame->curline));
-               /* w/2 because we're already doing 2 pixels */
-               rgbL1 = rgbL0 + (cam->width/2);
-
-               for (x=0; x < cam->width; x+=2) {
-                       rgbL0->r = bayL0->r;
-                       rgbL0->g = bayL0->g;
-                       rgbL0->b = bayL1->b;
-
-                       rgbL0->r2 = bayL0->r;
-                       rgbL0->g2 = bayL1->g;
-                       rgbL0->b2 = bayL1->b;
-
-                       rgbL1->r = bayL0->r;
-                       rgbL1->g = bayL1->g;
-                       rgbL1->b = bayL1->b;
-
-                       rgbL1->r2 = bayL0->r;
-                       rgbL1->g2 = bayL1->g;
-                       rgbL1->b2 = bayL1->b;
-
-                       rgbL0++;
-                       rgbL1++;
-
-                       bayL0++;
-                       bayL1++;
-               }
-
-               frame->seqRead_Length += cam->width*3*2;
-               frame->curline += 2;
-       }
-       /* See if we filled the frame */
-       if (frame->curline == cam->height) {
-               frame->frameState = FrameState_Done_Hold;
-               frame->curline = 0;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-/* taken from konicawc */
-static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
-       int ret;
-       int newsize;
-       int oldsize;
-       int x = vw->width;
-       int y = vw->height;
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-
-       if (x > 0 && y > 0) {
-               DEBUG(2, "trying to find size %d,%d", x, y);
-               for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
-                       if ((camera_sizes[newsize].width == x) &&
-                               (camera_sizes[newsize].height == y))
-                               break;
-               }
-       } else
-               newsize = cam->size;
-
-       if (newsize > MAX_FRAME_SIZE) {
-               DEBUG(1, "couldn't find size %d,%d", x, y);
-               return -EINVAL;
-       }
-
-       if (newsize == cam->size) {
-               DEBUG(1, "Nothing to do");
-               return 0;
-       }
-
-       qcm_stop_data(uvd);
-
-       if (cam->size != newsize) {
-               oldsize = cam->size;
-               cam->size = newsize;
-               ret = qcm_set_camera_size(uvd);
-               if (ret) {
-                       err("Couldn't set camera size, err=%d",ret);
-                       /* restore the original size */
-                       cam->size = oldsize;
-                       return ret;
-               }
-       }
-
-       /* Flush the input queue and clear any current frame in progress */
-
-       RingQueue_Flush(&uvd->dp);
-       if (uvd->curframe != -1) {
-               uvd->frame[uvd->curframe].curline = 0;
-               uvd->frame[uvd->curframe].seqRead_Length = 0;
-               uvd->frame[uvd->curframe].seqRead_Index = 0;
-       }
-
-       CHECK_RET(ret, qcm_start_data(uvd));
-       return 0;
-}
-
-static int qcm_configure_video(struct uvd *uvd)
-{
-       int ret;
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       uvd->vpic.colour = colour;
-       uvd->vpic.hue = hue;
-       uvd->vpic.brightness = brightness;
-       uvd->vpic.contrast = contrast;
-       uvd->vpic.whiteness = whiteness;
-       uvd->vpic.depth = 24;
-       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "QCM USB Camera");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-
-       uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
-       uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
-       uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
-       uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0 ;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-
-       CHECK_RET(ret, qcm_sensor_init(uvd));
-       return 0;
-}
-
-static int qcm_probe(struct usb_interface *intf,
-                       const struct usb_device_id *devid)
-{
-       int err;
-       struct uvd *uvd;
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct qcm *cam;
-       size_t buffer_size;
-       unsigned char video_ep;
-       struct usb_host_interface *interface;
-       struct usb_endpoint_descriptor *endpoint;
-       int i,j;
-       unsigned int ifacenum, ifacenum_inact=0;
-       __le16 sensor_id;
-
-       /* we don't support multiconfig cams */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       /* first check for the video interface and not
-       * the audio interface */
-       interface = &intf->cur_altsetting[0];
-       if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
-               || (interface->desc.bInterfaceSubClass !=
-                       USB_CLASS_VENDOR_SPEC))
-               return -ENODEV;
-
-       /*
-       walk through each endpoint in each setting in the interface
-       stop when we find the one that's an isochronous IN endpoint.
-       */
-       for (i=0; i < intf->num_altsetting; i++) {
-               interface = &intf->cur_altsetting[i];
-               ifacenum = interface->desc.bAlternateSetting;
-               /* walk the end points */
-               for (j=0; j < interface->desc.bNumEndpoints; j++) {
-                       endpoint = &interface->endpoint[j].desc;
-
-                       if (usb_endpoint_dir_out(endpoint))
-                               continue; /* not input then not good */
-
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-                       if (!buffer_size) {
-                               ifacenum_inact = ifacenum;
-                               continue; /* 0 pkt size is not what we want */
-                       }
-
-                       if (usb_endpoint_xfer_isoc(endpoint)) {
-                               video_ep = endpoint->bEndpointAddress;
-                               /* break out of the search */
-                               goto good_videoep;
-                       }
-               }
-       }
-       /* failed out since nothing useful was found */
-       err("No suitable endpoint was found\n");
-       return -ENODEV;
-
-good_videoep:
-       /* disable isochronous stream before doing anything else */
-       err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
-       if (err < 0) {
-               err("Failed to disable sensor stream");
-               return -EIO;
-       }
-
-       /*
-       Check that this is the same unknown sensor that is known to work. This
-       sensor is suspected to be the ST VV6422C001. I'll check the same value
-       that the qc-usb driver checks. This value is probably not even the
-       sensor ID since it matches the USB dev ID. Oh well. If it doesn't
-       match, it's probably a diff sensor so exit and apologize.
-       */
-       err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
-       if (err < 0) {
-               err("Couldn't read sensor values. Err %d\n",err);
-               return err;
-       }
-       if (sensor_id != cpu_to_le16(0x08F0)) {
-               err("Sensor ID %x != %x. Unsupported. Sorry\n",
-                       le16_to_cpu(sensor_id), (0x08F0));
-               return -ENODEV;
-       }
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (!uvd)
-               return -ENOMEM;
-
-       cam = (struct qcm *) uvd->user_data;
-
-       /* buf for doing demosaicing */
-       cam->scratch = kmalloc(324*2, GFP_KERNEL);
-       if (!cam->scratch) /* uvd freed in dereg */
-               return -ENOMEM;
-
-       /* yes, if we fail after here, cam->scratch gets freed
-       by qcm_free_uvd */
-
-       err = qcm_alloc_int_urb(cam);
-       if (err < 0)
-               return err;
-
-       /* yes, if we fail after here, int urb gets freed
-       by qcm_free_uvd */
-
-       RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
-       cam->width = camera_sizes[size].width;
-       cam->height = camera_sizes[size].height;
-       cam->size = size;
-
-       uvd->debug = debug;
-       uvd->flags = 0;
-       uvd->dev = dev;
-       uvd->iface = intf->altsetting->desc.bInterfaceNumber;
-       uvd->ifaceAltActive = ifacenum;
-       uvd->ifaceAltInactive = ifacenum_inact;
-       uvd->video_endp = video_ep;
-       uvd->iso_packet_len = buffer_size;
-       uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
-       uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-       uvd->canvas = VIDEOSIZE(320, 240);
-       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-       err = qcm_configure_video(uvd);
-       if (err) {
-               err("failed to configure video settings");
-               return err;
-       }
-
-       err = usbvideo_RegisterVideoDevice(uvd);
-       if (err) { /* the uvd gets freed in Deregister */
-               err("usbvideo_RegisterVideoDevice() failed.");
-               return err;
-       }
-
-       uvd->max_frame_size = (320 * 240 * 3);
-       qcm_register_input(cam, dev);
-       usb_set_intfdata(intf, uvd);
-       return 0;
-}
-
-static void qcm_free_uvd(struct uvd *uvd)
-{
-       struct qcm *cam = (struct qcm *) uvd->user_data;
-
-       kfree(cam->scratch);
-       qcm_unregister_input(cam);
-       qcm_free_int(cam);
-}
-
-static struct usbvideo_cb qcm_driver = {
-       .probe =                qcm_probe,
-       .setupOnOpen =          qcm_setup_on_open,
-       .processData =          qcm_process_isoc,
-       .setVideoMode =         qcm_set_video_mode,
-       .startDataPump =        qcm_start_data,
-       .stopDataPump =         qcm_stop_data,
-       .adjustPicture =        qcm_adjust_picture,
-       .userFree =             qcm_free_uvd
-};
-
-static int __init qcm_init(void)
-{
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-              DRIVER_DESC "\n");
-
-       return usbvideo_register(
-               &cams,
-               MAX_CAMERAS,
-               sizeof(struct qcm),
-               "QCM",
-               &qcm_driver,
-               THIS_MODULE,
-               qcm_table);
-}
-
-static void __exit qcm_exit(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
-module_param(colour, int, 0);
-MODULE_PARM_DESC(colour, "Initial colour");
-module_param(hue, int, 0);
-MODULE_PARM_DESC(hue, "Initial hue");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast");
-module_param(whiteness, int, 0);
-MODULE_PARM_DESC(whiteness, "Initial whiteness");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(qcm_init);
-module_exit(qcm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaya Kumar");
-MODULE_DESCRIPTION("QCM USB Camera");
-MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
deleted file mode 100644 (file)
index 17ace39..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef quickcam_messenger_h
-#define quickcam_messenger_h
-
-#ifndef CONFIG_INPUT
-/* if we're not using input we dummy out these functions */
-#define qcm_register_input(...)
-#define qcm_unregister_input(...)
-#define qcm_report_buttonstat(...)
-#define qcm_setup_input_int(...) 0
-#define qcm_stop_int_data(...)
-#define qcm_alloc_int_urb(...) 0
-#define qcm_free_int(...)
-#endif
-
-
-#define CHECK_RET(ret, expr) \
-       if ((ret = expr) < 0) return ret
-
-/* Control Registers for the STVV6422 ASIC
- * - this define is taken from the qc-usb-messenger code
- */
-#define STV_ISO_ENABLE         0x1440
-#define ISOC_PACKET_SIZE       1023
-
-/* Chip identification number including revision indicator */
-#define CMOS_SENSOR_IDREV      0xE00A
-
-struct rgb {
-       u8 b;
-       u8 g;
-       u8 r;
-       u8 b2;
-       u8 g2;
-       u8 r2;
-};
-
-struct bayL0 {
-       u8 g;
-       u8 r;
-};
-
-struct bayL1 {
-       u8 b;
-       u8 g;
-};
-
-struct cam_size {
-       u16     width;
-       u16     height;
-       u8      cmd;
-};
-
-static const struct cam_size camera_sizes[] = {
-       { 160, 120, 0xf },
-       { 320, 240, 0x2 },
-};
-
-enum frame_sizes {
-       SIZE_160X120    = 0,
-       SIZE_320X240    = 1,
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-struct qcm {
-       u16 colour;
-       u16 hue;
-       u16 brightness;
-       u16 contrast;
-       u16 whiteness;
-
-       u8 size;
-       int height;
-       int width;
-       u8 *scratch;
-       struct urb *button_urb;
-       u8 button_sts;
-       u8 button_sts_buf;
-
-#ifdef CONFIG_INPUT
-       struct input_dev *input;
-       char input_physname[64];
-#endif
-};
-
-struct regval {
-       u16 reg;
-       u8 val;
-};
-/* this table is derived from the
-qc-usb-messenger code */
-static const struct regval regval_table[] = {
-       { STV_ISO_ENABLE, 0x00 },
-       { 0x1436, 0x00 }, { 0x1432, 0x03 },
-       { 0x143a, 0xF9 }, { 0x0509, 0x38 },
-       { 0x050a, 0x38 }, { 0x050b, 0x38 },
-       { 0x050c, 0x2A }, { 0x050d, 0x01 },
-       { 0x1431, 0x00 }, { 0x1433, 0x34 },
-       { 0x1438, 0x18 }, { 0x1439, 0x00 },
-       { 0x143b, 0x05 }, { 0x143c, 0x00 },
-       { 0x143e, 0x01 }, { 0x143d, 0x00 },
-       { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
-       { 0x1500, 0xd0 }, { 0x1500, 0x50 },
-       { 0x1501, 0xaf }, { 0x1502, 0xc2 },
-       { 0x1503, 0x45 }, { 0x1505, 0x02 },
-       { 0x150e, 0x8e }, { 0x150f, 0x37 },
-       { 0x15c0, 0x00 },
-};
-
-static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
-
-#endif /* quickcam_messenger_h */
index 27a79f087b15c565004f44f14631be68ff78b890..a350fad0db432291f66a3be5073ecf0f2e4e00fe 100644 (file)
@@ -605,6 +605,26 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .get            = uvc_ctrl_get_zoom,
                .set            = uvc_ctrl_set_zoom,
        },
+       {
+               .id             = V4L2_CID_PAN_ABSOLUTE,
+               .name           = "Pan (Absolute)",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+               .size           = 32,
+               .offset         = 0,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_UNSIGNED,
+       },
+       {
+               .id             = V4L2_CID_TILT_ABSOLUTE,
+               .name           = "Tilt (Absolute)",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+               .size           = 32,
+               .offset         = 32,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_UNSIGNED,
+       },
        {
                .id             = V4L2_CID_PRIVACY,
                .name           = "Privacy",
@@ -623,7 +643,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
 
 static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
 {
-       return ctrl->data + id * ctrl->info->size;
+       return ctrl->uvc_data + id * ctrl->info->size;
 }
 
 static inline int uvc_test_bit(const __u8 *data, int bit)
@@ -678,6 +698,14 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
        int offset = mapping->offset;
        __u8 mask;
 
+       /* According to the v4l2 spec, writing any value to a button control
+        * should result in the action belonging to the button control being
+        * triggered. UVC devices however want to see a 1 written -> override
+        * value.
+        */
+       if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
+               value = -1;
+
        data += offset / 8;
        offset &= 7;
 
@@ -1265,13 +1293,15 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
  * Control and mapping handling
  */
 
-static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+static int uvc_ctrl_add_ctrl(struct uvc_device *dev,
        struct uvc_control_info *info)
 {
        struct uvc_entity *entity;
        struct uvc_control *ctrl = NULL;
-       int ret, found = 0;
+       int ret = 0, found = 0;
        unsigned int i;
+       u8 *uvc_info;
+       u8 *uvc_data;
 
        list_for_each_entry(entity, &dev->entities, list) {
                if (!uvc_entity_match_guid(entity, info->entity))
@@ -1290,56 +1320,69 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
        }
 
        if (!found)
-               return;
+               return 0;
+
+       uvc_data = kmalloc(info->size * UVC_CTRL_DATA_LAST + 1, GFP_KERNEL);
+       if (uvc_data == NULL)
+               return -ENOMEM;
+
+       uvc_info = uvc_data + info->size * UVC_CTRL_DATA_LAST;
 
        if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
                /* Check if the device control information and length match
                 * the user supplied information.
                 */
-               __u32 flags;
-               __le16 size;
-               __u8 inf;
-
                ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
-                       dev->intfnum, info->selector, (__u8 *)&size, 2);
+                                    dev->intfnum, info->selector, uvc_data, 2);
                if (ret < 0) {
                        uvc_trace(UVC_TRACE_CONTROL,
                                "GET_LEN failed on control %pUl/%u (%d).\n",
                                info->entity, info->selector, ret);
-                       return;
+                       goto done;
                }
 
-               if (info->size != le16_to_cpu(size)) {
+               if (info->size != le16_to_cpu(*(__le16 *)uvc_data)) {
                        uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
                                "doesn't match user supplied value.\n",
                                info->entity, info->selector);
-                       return;
+                       ret = -EINVAL;
+                       goto done;
                }
 
                ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
-                       dev->intfnum, info->selector, &inf, 1);
+                                    dev->intfnum, info->selector, uvc_info, 1);
                if (ret < 0) {
                        uvc_trace(UVC_TRACE_CONTROL,
                                "GET_INFO failed on control %pUl/%u (%d).\n",
                                info->entity, info->selector, ret);
-                       return;
+                       goto done;
                }
 
-               flags = info->flags;
-               if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
-                   ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+               if (((info->flags & UVC_CONTROL_GET_CUR) &&
+                   !(*uvc_info & UVC_CONTROL_CAP_GET)) ||
+                   ((info->flags & UVC_CONTROL_SET_CUR) &&
+                   !(*uvc_info & UVC_CONTROL_CAP_SET))) {
                        uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
                                "don't match supported operations.\n",
                                info->entity, info->selector);
-                       return;
+                       ret = -EINVAL;
+                       goto done;
                }
        }
 
        ctrl->info = info;
-       ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
+       ctrl->uvc_data = uvc_data;
+       ctrl->uvc_info = uvc_info;
+
        uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
                "entity %u\n", ctrl->info->entity, ctrl->info->selector,
                dev->udev->devpath, entity->id);
+
+done:
+       if (ret < 0)
+               kfree(uvc_data);
+
+       return ret;
 }
 
 /*
@@ -1572,12 +1615,34 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
 
        list_for_each_entry(entity, &dev->entities, list) {
                for (i = 0; i < entity->ncontrols; ++i)
-                       kfree(entity->controls[i].data);
+                       kfree(entity->controls[i].uvc_data);
 
                kfree(entity->controls);
        }
 }
 
+void uvc_ctrl_cleanup(void)
+{
+       struct uvc_control_info *info;
+       struct uvc_control_info *ni;
+       struct uvc_control_mapping *mapping;
+       struct uvc_control_mapping *nm;
+
+       list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
+               if (!(info->flags & UVC_CONTROL_EXTENSION))
+                       continue;
+
+               list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
+                       list_del(&mapping->list);
+                       kfree(mapping->menu_info);
+                       kfree(mapping);
+               }
+
+               list_del(&info->list);
+               kfree(info);
+       }
+}
+
 void uvc_ctrl_init(void)
 {
        struct uvc_control_info *ctrl = uvc_ctrls;
index 838b56f097cf816f9221f97a63fd468f49e7bdac..7eaf99b22a48d9001f844772fcfa43483fbe9b9f 100644 (file)
@@ -637,14 +637,13 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        }
        streaming->header.bControlSize = n;
 
-       streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+       streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
+                                               GFP_KERNEL);
        if (streaming->header.bmaControls == NULL) {
                ret = -ENOMEM;
                goto error;
        }
 
-       memcpy(streaming->header.bmaControls, &buffer[size], p*n);
-
        buflen -= buffer[0];
        buffer += buffer[0];
 
@@ -2174,6 +2173,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
+       /* Manta MM-353 Plako */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x18ec,
+         .idProduct            = 0x3188,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* FSC WebCam V30S */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2261,6 +2269,7 @@ static int __init uvc_init(void)
 static void __exit uvc_cleanup(void)
 {
        usb_deregister(&uvc_driver.driver);
+       uvc_ctrl_cleanup();
 }
 
 module_init(uvc_init);
index 7c9ab2933496ea4515f6b0544c561b7769f87052..86db32697b805dad926be84119082147f525e885 100644 (file)
 
 #include "uvcvideo.h"
 
+/* ------------------------------------------------------------------------
+ * UVC ioctls
+ */
+static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
+{
+       struct uvc_control_mapping *map;
+       unsigned int size;
+       int ret;
+
+       map = kzalloc(sizeof *map, GFP_KERNEL);
+       if (map == NULL)
+               return -ENOMEM;
+
+       map->id = xmap->id;
+       memcpy(map->name, xmap->name, sizeof map->name);
+       memcpy(map->entity, xmap->entity, sizeof map->entity);
+       map->selector = xmap->selector;
+       map->size = xmap->size;
+       map->offset = xmap->offset;
+       map->v4l2_type = xmap->v4l2_type;
+       map->data_type = xmap->data_type;
+
+       switch (xmap->v4l2_type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_BOOLEAN:
+       case V4L2_CTRL_TYPE_BUTTON:
+               break;
+
+       case V4L2_CTRL_TYPE_MENU:
+               if (old) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               size = xmap->menu_count * sizeof(*map->menu_info);
+               map->menu_info = kmalloc(size, GFP_KERNEL);
+               if (map->menu_info == NULL) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
+                       ret = -EFAULT;
+                       goto done;
+               }
+
+               map->menu_count = xmap->menu_count;
+               break;
+
+       default:
+               ret = -EINVAL;
+               goto done;
+       }
+
+       ret = uvc_ctrl_add_mapping(map);
+
+done:
+       if (ret < 0) {
+               kfree(map->menu_info);
+               kfree(map);
+       }
+
+       return ret;
+}
+
 /* ------------------------------------------------------------------------
  * V4L2 interface
  */
@@ -451,7 +516,7 @@ static int uvc_v4l2_open(struct file *file)
 
 static int uvc_v4l2_release(struct file *file)
 {
-       struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_fh *handle = file->private_data;
        struct uvc_streaming *stream = handle->stream;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
@@ -482,7 +547,7 @@ static int uvc_v4l2_release(struct file *file)
 static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = video_devdata(file);
-       struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_fh *handle = file->private_data;
        struct uvc_video_chain *chain = handle->chain;
        struct uvc_streaming *stream = handle->stream;
        long ret = 0;
@@ -963,6 +1028,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
+               if (xinfo->size == 0)
+                       return -EINVAL;
+
                info = kzalloc(sizeof *info, GFP_KERNEL);
                if (info == NULL)
                        return -ENOMEM;
@@ -974,7 +1042,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                info->flags = xinfo->flags;
 
                info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
-                               UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+                              UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
+                              UVC_CONTROL_EXTENSION;
 
                ret = uvc_ctrl_add_info(info);
                if (ret < 0)
@@ -982,32 +1051,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                break;
        }
 
+       case UVCIOC_CTRL_MAP_OLD:
        case UVCIOC_CTRL_MAP:
-       {
-               struct uvc_xu_control_mapping *xmap = arg;
-               struct uvc_control_mapping *map;
-
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               map = kzalloc(sizeof *map, GFP_KERNEL);
-               if (map == NULL)
-                       return -ENOMEM;
-
-               map->id = xmap->id;
-               memcpy(map->name, xmap->name, sizeof map->name);
-               memcpy(map->entity, xmap->entity, sizeof map->entity);
-               map->selector = xmap->selector;
-               map->size = xmap->size;
-               map->offset = xmap->offset;
-               map->v4l2_type = xmap->v4l2_type;
-               map->data_type = xmap->data_type;
-
-               ret = uvc_ctrl_add_mapping(map);
-               if (ret < 0)
-                       kfree(map);
-               break;
-       }
+               return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
 
        case UVCIOC_CTRL_GET:
                return uvc_xu_ctrl_query(chain, arg, 0);
@@ -1067,7 +1116,7 @@ static const struct vm_operations_struct uvc_vm_ops = {
 
 static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_fh *handle = file->private_data;
        struct uvc_streaming *stream = handle->stream;
        struct uvc_video_queue *queue = &stream->queue;
        struct uvc_buffer *uninitialized_var(buffer);
@@ -1122,7 +1171,7 @@ done:
 
 static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
-       struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_fh *handle = file->private_data;
        struct uvc_streaming *stream = handle->stream;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
index d1f88406a5e7cf784b108d6c0bc1e3584871d742..ac272456fbfdf997f177f99842fdfaef6529a6db 100644 (file)
@@ -27,6 +27,8 @@
 #define UVC_CONTROL_RESTORE    (1 << 6)
 /* Control can be updated by the camera. */
 #define UVC_CONTROL_AUTO_UPDATE        (1 << 7)
+/* Control is an extension unit control. */
+#define UVC_CONTROL_EXTENSION  (1 << 8)
 
 #define UVC_CONTROL_GET_RANGE  (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
                                 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
@@ -40,6 +42,15 @@ struct uvc_xu_control_info {
        __u32 flags;
 };
 
+struct uvc_menu_info {
+       __u32 value;
+       __u8 name[32];
+};
+
+struct uvc_xu_control_mapping_old {
+       __u8 reserved[64];
+};
+
 struct uvc_xu_control_mapping {
        __u32 id;
        __u8 name[32];
@@ -50,6 +61,11 @@ struct uvc_xu_control_mapping {
        __u8 offset;
        enum v4l2_ctrl_type v4l2_type;
        __u32 data_type;
+
+       struct uvc_menu_info __user *menu_info;
+       __u32 menu_count;
+
+       __u32 reserved[4];
 };
 
 struct uvc_xu_control {
@@ -60,6 +76,7 @@ struct uvc_xu_control {
 };
 
 #define UVCIOC_CTRL_ADD                _IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP_OLD    _IOWR('U', 2, struct uvc_xu_control_mapping_old)
 #define UVCIOC_CTRL_MAP                _IOWR('U', 2, struct uvc_xu_control_mapping)
 #define UVCIOC_CTRL_GET                _IOWR('U', 3, struct uvc_xu_control)
 #define UVCIOC_CTRL_SET                _IOW('U', 4, struct uvc_xu_control)
@@ -179,30 +196,6 @@ struct uvc_device;
 /* TODO: Put the most frequently accessed fields at the beginning of
  * structures to maximize cache efficiency.
  */
-struct uvc_streaming_control {
-       __u16 bmHint;
-       __u8  bFormatIndex;
-       __u8  bFrameIndex;
-       __u32 dwFrameInterval;
-       __u16 wKeyFrameRate;
-       __u16 wPFrameRate;
-       __u16 wCompQuality;
-       __u16 wCompWindowSize;
-       __u16 wDelay;
-       __u32 dwMaxVideoFrameSize;
-       __u32 dwMaxPayloadTransferSize;
-       __u32 dwClockFrequency;
-       __u8  bmFramingInfo;
-       __u8  bPreferedVersion;
-       __u8  bMinVersion;
-       __u8  bMaxVersion;
-};
-
-struct uvc_menu_info {
-       __u32 value;
-       __u8 name[32];
-};
-
 struct uvc_control_info {
        struct list_head list;
        struct list_head mappings;
@@ -250,7 +243,8 @@ struct uvc_control {
             modified : 1,
             cached : 1;
 
-       __u8 *data;
+       __u8 *uvc_data;
+       __u8 *uvc_info;
 };
 
 struct uvc_format_desc {
@@ -625,6 +619,7 @@ extern int uvc_ctrl_init_device(struct uvc_device *dev);
 extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
 extern int uvc_ctrl_resume_device(struct uvc_device *dev);
 extern void uvc_ctrl_init(void);
+extern void uvc_ctrl_cleanup(void);
 
 extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
 extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
index 0ca7ec9ca90269de9d9cffa890ebf0b01ef886b2..9e89bf617790b46b67ce7cc9155d28df9d8bf9ed 100644 (file)
@@ -410,7 +410,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
        int minor_offset = 0;
        int minor_cnt = VIDEO_NUM_DEVICES;
        const char *name_base;
-       void *priv = video_get_drvdata(vdev);
+       void *priv = vdev->dev.p;
 
        /* A minor value of -1 marks this video device as never
           having been registered */
@@ -536,9 +536,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
 
        /* Part 4: register the device with sysfs */
        memset(&vdev->dev, 0, sizeof(vdev->dev));
-       /* The memset above cleared the device's drvdata, so
+       /* The memset above cleared the device's device_private, so
           put back the copy we made earlier. */
-       video_set_drvdata(vdev, priv);
+       vdev->dev.p = priv;
        vdev->dev.class = &video_class;
        vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
        if (vdev->parent)
index 7d3378437ded6f6a95093c461ed345bf0f393ad8..ce1595bef6291acea2af5b570c310eeb455aaf3d 100644 (file)
@@ -52,18 +52,18 @@ MODULE_LICENSE("GPL");
 #define CALL(q, f, arg...)                                             \
        ((q->int_ops->f) ? q->int_ops->f(arg) : 0)
 
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
 {
        struct videobuf_buffer *vb;
 
        BUG_ON(q->msize < sizeof(*vb));
 
-       if (!q->int_ops || !q->int_ops->alloc) {
+       if (!q->int_ops || !q->int_ops->alloc_vb) {
                printk(KERN_ERR "No specific ops defined!\n");
                BUG();
        }
 
-       vb = q->int_ops->alloc(q->msize);
+       vb = q->int_ops->alloc_vb(q->msize);
        if (NULL != vb) {
                init_waitqueue_head(&vb->done);
                vb->magic = MAGIC_BUFFER;
@@ -71,7 +71,7 @@ struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
 
        return vb;
 }
-EXPORT_SYMBOL_GPL(videobuf_alloc);
+EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
 
 #define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
                                vb->state != VIDEOBUF_QUEUED)
@@ -195,6 +195,45 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
 }
 EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
 
+/**
+ * __videobuf_free() - free all the buffers and their control structures
+ *
+ * This function can only be called if streaming/reading is off, i.e. no buffers
+ * are under control of the driver.
+ */
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_free(struct videobuf_queue *q)
+{
+       int i;
+
+       dprintk(1, "%s\n", __func__);
+       if (!q)
+               return 0;
+
+       if (q->streaming || q->reading) {
+               dprintk(1, "Cannot free buffers when streaming or reading\n");
+               return -EBUSY;
+       }
+
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+       for (i = 0; i < VIDEO_MAX_FRAME; i++)
+               if (q->bufs[i] && q->bufs[i]->map) {
+                       dprintk(1, "Cannot free mmapped buffers\n");
+                       return -EBUSY;
+               }
+
+       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+               if (NULL == q->bufs[i])
+                       continue;
+               q->ops->buf_release(q, q->bufs[i]);
+               kfree(q->bufs[i]);
+               q->bufs[i] = NULL;
+       }
+
+       return 0;
+}
+
 /* Locking: Caller holds q->vb_lock */
 void videobuf_queue_cancel(struct videobuf_queue *q)
 {
@@ -308,36 +347,11 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
        b->sequence  = vb->field_count >> 1;
 }
 
-/* Locking: Caller holds q->vb_lock */
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
-       int i;
-
-       if (!q)
-               return 0;
-
-       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
-       for (i = 0; i < VIDEO_MAX_FRAME; i++)
-               if (q->bufs[i] && q->bufs[i]->map)
-                       return -EBUSY;
-
-       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-               if (NULL == q->bufs[i])
-                       continue;
-               q->ops->buf_release(q, q->bufs[i]);
-               kfree(q->bufs[i]);
-               q->bufs[i] = NULL;
-       }
-
-       return 0;
-}
-
 int videobuf_mmap_free(struct videobuf_queue *q)
 {
        int ret;
        mutex_lock(&q->vb_lock);
-       ret = __videobuf_mmap_free(q);
+       ret = __videobuf_free(q);
        mutex_unlock(&q->vb_lock);
        return ret;
 }
@@ -353,13 +367,13 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
 
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       err = __videobuf_mmap_free(q);
+       err = __videobuf_free(q);
        if (0 != err)
                return err;
 
        /* Allocate and initialize buffers */
        for (i = 0; i < bcount; i++) {
-               q->bufs[i] = videobuf_alloc(q);
+               q->bufs[i] = videobuf_alloc_vb(q);
 
                if (NULL == q->bufs[i])
                        break;
@@ -766,7 +780,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        /* setup stuff */
-       q->read_buf = videobuf_alloc(q);
+       q->read_buf = videobuf_alloc_vb(q);
        if (NULL == q->read_buf)
                return -ENOMEM;
 
@@ -871,7 +885,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        if (NULL == q->read_buf) {
                /* need to capture a new frame */
                retval = -ENOMEM;
-               q->read_buf = videobuf_alloc(q);
+               q->read_buf = videobuf_alloc_vb(q);
 
                dprintk(1, "video alloc=0x%p\n", q->read_buf);
                if (NULL == q->read_buf)
@@ -970,7 +984,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
        int i;
 
        videobuf_queue_cancel(q);
-       __videobuf_mmap_free(q);
+       __videobuf_free(q);
        INIT_LIST_HEAD(&q->stream);
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
index 74730c624cfcba0809fb45069bf3e1854c963412..372b87efcd0538ec6c91c1bb45749177294f7442 100644 (file)
@@ -190,7 +190,7 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
        return ret;
 }
 
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 {
        struct videobuf_dma_contig_memory *mem;
        struct videobuf_buffer *vb;
@@ -280,8 +280,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
                return -ENOMEM;
 
        buf->map = map;
-       map->start = vma->vm_start;
-       map->end = vma->vm_end;
        map->q = q;
 
        buf->baddr = vma->vm_start;
@@ -338,7 +336,7 @@ error:
 static struct videobuf_qtype_ops qops = {
        .magic        = MAGIC_QTYPE_OPS,
 
-       .alloc        = __videobuf_alloc,
+       .alloc_vb     = __videobuf_alloc_vb,
        .iolock       = __videobuf_iolock,
        .mmap_mapper  = __videobuf_mmap_mapper,
        .vaddr        = __videobuf_to_vaddr,
index 8359e6badd36789b9380c6a83ccca153e0d2cb71..06f9a9c2a39add9256a58850d0cf5c4b0c52bf5b 100644 (file)
@@ -57,7 +57,13 @@ MODULE_LICENSE("GPL");
 
 /* --------------------------------------------------------------------- */
 
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+/*
+ * Return a scatterlist for some page-aligned vmalloc()'ed memory
+ * block (NULL on errors).  Memory for the scatterlist is allocated
+ * using kmalloc.  The caller must free the memory.
+ */
+static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt,
+                                                 int nr_pages)
 {
        struct scatterlist *sglist;
        struct page *pg;
@@ -81,10 +87,14 @@ err:
        vfree(sglist);
        return NULL;
 }
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
 
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
-                                        int offset)
+/*
+ * Return a scatterlist for a an array of userpages (NULL on errors).
+ * Memory for the scatterlist is allocated using kmalloc.  The caller
+ * must free the memory.
+ */
+static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
+                                               int nr_pages, int offset)
 {
        struct scatterlist *sglist;
        int i;
@@ -201,17 +211,17 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
        dprintk(1, "init kernel [%d pages]\n", nr_pages);
 
        dma->direction = direction;
-       dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
-       if (NULL == dma->vmalloc) {
+       dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+       if (NULL == dma->vaddr) {
                dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
                return -ENOMEM;
        }
 
        dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
-                               (unsigned long)dma->vmalloc,
+                               (unsigned long)dma->vaddr,
                                nr_pages << PAGE_SHIFT);
 
-       memset(dma->vmalloc, 0, nr_pages << PAGE_SHIFT);
+       memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
        dma->nr_pages = nr_pages;
 
        return 0;
@@ -235,7 +245,7 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
 }
 EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
 
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
 {
        MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
        BUG_ON(0 == dma->nr_pages);
@@ -244,8 +254,8 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
                dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
                                                   dma->offset);
        }
-       if (dma->vmalloc) {
-               dma->sglist = videobuf_vmalloc_to_sg(dma->vmalloc,
+       if (dma->vaddr) {
+               dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr,
                                                     dma->nr_pages);
        }
        if (dma->bus_addr) {
@@ -263,7 +273,7 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
                return -ENOMEM;
        }
        if (!dma->bus_addr) {
-               dma->sglen = dma_map_sg(q->dev, dma->sglist,
+               dma->sglen = dma_map_sg(dev, dma->sglist,
                                        dma->nr_pages, dma->direction);
                if (0 == dma->sglen) {
                        printk(KERN_WARNING
@@ -279,14 +289,14 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
 }
 EXPORT_SYMBOL_GPL(videobuf_dma_map);
 
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
 {
        MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 
        if (!dma->sglen)
                return 0;
 
-       dma_unmap_sg(q->dev, dma->sglist, dma->sglen, dma->direction);
+       dma_unmap_sg(dev, dma->sglist, dma->sglen, dma->direction);
 
        vfree(dma->sglist);
        dma->sglist = NULL;
@@ -309,8 +319,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
                dma->pages = NULL;
        }
 
-       vfree(dma->vmalloc);
-       dma->vmalloc = NULL;
+       vfree(dma->vaddr);
+       dma->vaddr = NULL;
 
        if (dma->bus_addr)
                dma->bus_addr = 0;
@@ -322,28 +332,6 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
 
 /* --------------------------------------------------------------------- */
 
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
-{
-       struct videobuf_queue q;
-
-       q.dev = dev;
-
-       return videobuf_dma_map(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
-
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
-{
-       struct videobuf_queue q;
-
-       q.dev = dev;
-
-       return videobuf_dma_unmap(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
-
-/* --------------------------------------------------------------------- */
-
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        struct videobuf_mapping *map = vma->vm_private_data;
@@ -428,7 +416,7 @@ static const struct vm_operations_struct videobuf_vm_ops = {
        struct videobuf_dma_sg_memory
  */
 
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 {
        struct videobuf_dma_sg_memory *mem;
        struct videobuf_buffer *vb;
@@ -456,7 +444,7 @@ static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
 
        MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
 
-       return mem->dma.vmalloc;
+       return mem->dma.vaddr;
 }
 
 static int __videobuf_iolock(struct videobuf_queue *q,
@@ -520,7 +508,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
        default:
                BUG();
        }
-       err = videobuf_dma_map(q, &mem->dma);
+       err = videobuf_dma_map(q->dev, &mem->dma);
        if (0 != err)
                return err;
 
@@ -620,8 +608,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
        }
 
        map->count    = 1;
-       map->start    = vma->vm_start;
-       map->end      = vma->vm_end;
        map->q        = q;
        vma->vm_ops   = &videobuf_vm_ops;
        vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
@@ -638,7 +624,7 @@ done:
 static struct videobuf_qtype_ops sg_ops = {
        .magic        = MAGIC_QTYPE_OPS,
 
-       .alloc        = __videobuf_alloc,
+       .alloc_vb     = __videobuf_alloc_vb,
        .iolock       = __videobuf_iolock,
        .sync         = __videobuf_sync,
        .mmap_mapper  = __videobuf_mmap_mapper,
@@ -654,7 +640,7 @@ void *videobuf_sg_alloc(size_t size)
 
        q.msize = size;
 
-       return videobuf_alloc(&q);
+       return videobuf_alloc_vb(&q);
 }
 EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
 
index 583728f4c221a4ce1eaf3f78d177758941b2f581..e7fe31d54f07258b9fbc333808fc9b34f7a78609 100644 (file)
@@ -102,10 +102,10 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                                   called with IRQ's disabled
                                 */
                                dprintk(1, "%s: buf[%d] freeing (%p)\n",
-                                       __func__, i, mem->vmalloc);
+                                       __func__, i, mem->vaddr);
 
-                               vfree(mem->vmalloc);
-                               mem->vmalloc = NULL;
+                               vfree(mem->vaddr);
+                               mem->vaddr = NULL;
                        }
 
                        q->bufs[i]->map   = NULL;
@@ -135,7 +135,7 @@ static const struct vm_operations_struct videobuf_vm_ops = {
        struct videobuf_dma_sg_memory
  */
 
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 {
        struct videobuf_vmalloc_memory *mem;
        struct videobuf_buffer *vb;
@@ -170,7 +170,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
                dprintk(1, "%s memory method MMAP\n", __func__);
 
                /* All handling should be done by __videobuf_mmap_mapper() */
-               if (!mem->vmalloc) {
+               if (!mem->vaddr) {
                        printk(KERN_ERR "memory is not alloced/mmapped.\n");
                        return -EINVAL;
                }
@@ -189,13 +189,13 @@ static int __videobuf_iolock(struct videobuf_queue *q,
                 * read() method.
                 */
 
-               mem->vmalloc = vmalloc_user(pages);
-               if (!mem->vmalloc) {
+               mem->vaddr = vmalloc_user(pages);
+               if (!mem->vaddr) {
                        printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
                        return -ENOMEM;
                }
                dprintk(1, "vmalloc is at addr %p (%d pages)\n",
-                       mem->vmalloc, pages);
+                       mem->vaddr, pages);
 
 #if 0
                int rc;
@@ -245,8 +245,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
                return -ENOMEM;
 
        buf->map = map;
-       map->start = vma->vm_start;
-       map->end   = vma->vm_end;
        map->q     = q;
 
        buf->baddr = vma->vm_start;
@@ -256,18 +254,18 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
        pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
-       mem->vmalloc = vmalloc_user(pages);
-       if (!mem->vmalloc) {
+       mem->vaddr = vmalloc_user(pages);
+       if (!mem->vaddr) {
                printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
                goto error;
        }
-       dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages);
+       dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
 
        /* Try to remap memory */
-       retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+       retval = remap_vmalloc_range(vma, mem->vaddr, 0);
        if (retval < 0) {
                printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
-               vfree(mem->vmalloc);
+               vfree(mem->vaddr);
                goto error;
        }
 
@@ -293,7 +291,7 @@ error:
 static struct videobuf_qtype_ops qops = {
        .magic        = MAGIC_QTYPE_OPS,
 
-       .alloc        = __videobuf_alloc,
+       .alloc_vb     = __videobuf_alloc_vb,
        .iolock       = __videobuf_iolock,
        .mmap_mapper  = __videobuf_mmap_mapper,
        .vaddr        = videobuf_to_vmalloc,
@@ -319,7 +317,7 @@ void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
        BUG_ON(!mem);
        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
-       return mem->vmalloc;
+       return mem->vaddr;
 }
 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 
@@ -341,8 +339,8 @@ void videobuf_vmalloc_free(struct videobuf_buffer *buf)
 
        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
-       vfree(mem->vmalloc);
-       mem->vmalloc = NULL;
+       vfree(mem->vaddr);
+       mem->vaddr = NULL;
 
        return;
 }
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
deleted file mode 100644 (file)
index d807eea..0000000
+++ /dev/null
@@ -1,3620 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * - Memory management code from bttv driver by Ralph Metzler,             *
- *   Marcus Metzler and Gerd Knorr.                                        *
- * - I2C interface to kernel, high-level image sensor control routines and *
- *   some symbolic names from OV511 driver by Mark W. McClelland.          *
- * - Low-level I2C fast write function by Piotr Czerczak.                  *
- * - Low-level I2C read function by Frederic Jouault.                      *
- *                                                                         *
- * This program is free software; 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/kernel.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <linux/page-flags.h>
-#include <linux/videodev.h>
-#include <media/v4l2-ioctl.h>
-
-#include "w9968cf.h"
-#include "w9968cf_decoder.h"
-
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
-
-/****************************************************************************
- * Module macros and parameters                                             *
- ****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, winbond_id_table);
-
-MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
-MODULE_VERSION(W9968CF_MODULE_VERSION);
-MODULE_LICENSE(W9968CF_MODULE_LICENSE);
-MODULE_SUPPORTED_DEVICE("Video");
-
-static unsigned short simcams = W9968CF_SIMCAMS;
-static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
-static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                    W9968CF_PACKET_SIZE};
-static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                      W9968CF_BUFFERS};
-static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                             W9968CF_DOUBLE_BUFFER};
-static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
-static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] =
-                                     W9968CF_FILTER_TYPE};
-static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
-static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                        W9968CF_DECOMPRESSION};
-static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
-static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
-static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
-static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
-static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
-static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                    W9968CF_LIGHTFREQ};
-static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
-                             W9968CF_BANDINGFILTER};
-static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
-static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
-static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
-static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                   W9968CF_BRIGHTNESS};
-static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
-static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
-static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                 W9968CF_CONTRAST};
-static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-                                  W9968CF_WHITENESS};
-#ifdef W9968CF_DEBUG
-static unsigned short debug = W9968CF_DEBUG_LEVEL;
-static int specific_debug = W9968CF_SPECIFIC_DEBUG;
-#endif
-
-static unsigned int param_nv[24]; /* number of values per parameter */
-
-module_param(simcams, ushort, 0644);
-module_param_array(video_nr, short, &param_nv[0], 0444);
-module_param_array(packet_size, uint, &param_nv[1], 0444);
-module_param_array(max_buffers, ushort, &param_nv[2], 0444);
-module_param_array(double_buffer, bool, &param_nv[3], 0444);
-module_param_array(clamping, bool, &param_nv[4], 0444);
-module_param_array(filter_type, ushort, &param_nv[5], 0444);
-module_param_array(largeview, bool, &param_nv[6], 0444);
-module_param_array(decompression, ushort, &param_nv[7], 0444);
-module_param_array(upscaling, bool, &param_nv[8], 0444);
-module_param_array(force_palette, ushort, &param_nv[9], 0444);
-module_param_array(force_rgb, ushort, &param_nv[10], 0444);
-module_param_array(autobright, bool, &param_nv[11], 0444);
-module_param_array(autoexp, bool, &param_nv[12], 0444);
-module_param_array(lightfreq, ushort, &param_nv[13], 0444);
-module_param_array(bandingfilter, bool, &param_nv[14], 0444);
-module_param_array(clockdiv, short, &param_nv[15], 0444);
-module_param_array(backlight, bool, &param_nv[16], 0444);
-module_param_array(mirror, bool, &param_nv[17], 0444);
-module_param_array(monochrome, bool, &param_nv[18], 0444);
-module_param_array(brightness, uint, &param_nv[19], 0444);
-module_param_array(hue, uint, &param_nv[20], 0444);
-module_param_array(colour, uint, &param_nv[21], 0444);
-module_param_array(contrast, uint, &param_nv[22], 0444);
-module_param_array(whiteness, uint, &param_nv[23], 0444);
-#ifdef W9968CF_DEBUG
-module_param(debug, ushort, 0644);
-module_param(specific_debug, bool, 0644);
-#endif
-
-MODULE_PARM_DESC(simcams,
-                "\n<n> Number of cameras allowed to stream simultaneously."
-                "\nn may vary from 0 to "
-                __MODULE_STRING(W9968CF_MAX_DEVICES)"."
-                "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
-                "\n");
-MODULE_PARM_DESC(video_nr,
-                "\n<-1|n[,...]> Specify V4L minor mode number."
-                "\n -1 = use next available (default)"
-                "\n  n = use minor number n (integer >= 0)"
-                "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
-                " cameras this way."
-                "\nFor example:"
-                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                "\nthe second camera and use auto for the first"
-                "\none and for every other camera."
-                "\n");
-MODULE_PARM_DESC(packet_size,
-                "\n<n[,...]> Specify the maximum data payload"
-                "\nsize in bytes for alternate settings, for each device."
-                "\nn is scaled between 63 and 1023 "
-                "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
-                "\n");
-MODULE_PARM_DESC(max_buffers,
-                "\n<n[,...]> For advanced users."
-                "\nSpecify the maximum number of video frame buffers"
-                "\nto allocate for each device, from 2 to "
-                __MODULE_STRING(W9968CF_MAX_BUFFERS)
-                ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
-                "\n");
-MODULE_PARM_DESC(double_buffer,
-                "\n<0|1[,...]> "
-                "Hardware double buffering: 0 disabled, 1 enabled."
-                "\nIt should be enabled if you want smooth video output: if"
-                "\nyou obtain out of sync. video, disable it, or try to"
-                "\ndecrease the 'clockdiv' module parameter value."
-                "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(clamping,
-                "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
-                "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(filter_type,
-                "\n<0|1|2[,...]> Video filter type."
-                "\n0 none, 1 (1-2-1) 3-tap filter, "
-                "2 (2-3-6-3-2) 5-tap filter."
-                "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
-                " for every device."
-                "\nThe filter is used to reduce noise and aliasing artifacts"
-                "\nproduced by the CCD or CMOS image sensor, and the scaling"
-                " process."
-                "\n");
-MODULE_PARM_DESC(largeview,
-                "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
-                "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(upscaling,
-                "\n<0|1[,...]> Software scaling (for non-compressed video):"
-                "\n0 disabled, 1 enabled."
-                "\nDisable it if you have a slow CPU or you don't have"
-                " enough memory."
-                "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
-                " for every device."
-                "\nIf 'w9968cf-vpp' is not present, this parameter is"
-                " set to 0."
-                "\n");
-MODULE_PARM_DESC(decompression,
-                "\n<0|1|2[,...]> Software video decompression:"
-                "\n- 0 disables decompression (doesn't allow formats needing"
-                " decompression)"
-                "\n- 1 forces decompression (allows formats needing"
-                " decompression only);"
-                "\n- 2 allows any permitted formats."
-                "\nFormats supporting compressed video are YUV422P and"
-                " YUV420P/YUV420 "
-                "\nin any resolutions where both width and height are "
-                "a multiple of 16."
-                "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
-                " for every device."
-                "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
-                "\nnot allowed; in this case this parameter is set to 2."
-                "\n");
-MODULE_PARM_DESC(force_palette,
-                "\n<0"
-                "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
-                "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
-                "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
-                "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
-                "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
-                "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
-                "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
-                "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
-                "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
-                "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
-                "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
-                "[,...]>"
-                " Force picture palette."
-                "\nIn order:"
-                "\n- 0 allows any of the following formats:"
-                "\n- UYVY    16 bpp - Original video, compression disabled"
-                "\n- YUV420  12 bpp - Original video, compression enabled"
-                "\n- YUV422P 16 bpp - Original video, compression enabled"
-                "\n- YUV420P 12 bpp - Original video, compression enabled"
-                "\n- YUVY    16 bpp - Software conversion from UYVY"
-                "\n- YUV422  16 bpp - Software conversion from UYVY"
-                "\n- GREY     8 bpp - Software conversion from UYVY"
-                "\n- RGB555  16 bpp - Software conversion from UYVY"
-                "\n- RGB565  16 bpp - Software conversion from UYVY"
-                "\n- RGB24   24 bpp - Software conversion from UYVY"
-                "\n- RGB32   32 bpp - Software conversion from UYVY"
-                "\nWhen not 0, this parameter will override 'decompression'."
-                "\nDefault value is 0 for every device."
-                "\nInitial palette is "
-                __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
-                "\nIf 'w9968cf-vpp' is not present, this parameter is"
-                " set to 9 (UYVY)."
-                "\n");
-MODULE_PARM_DESC(force_rgb,
-                "\n<0|1[,...]> Read RGB video data instead of BGR:"
-                "\n 1 = use RGB component ordering."
-                "\n 0 = use BGR component ordering."
-                "\nThis parameter has effect when using RGBX palettes only."
-                "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(autobright,
-                "\n<0|1[,...]> Image sensor automatically changes brightness:"
-                "\n 0 = no, 1 = yes"
-                "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(autoexp,
-                "\n<0|1[,...]> Image sensor automatically changes exposure:"
-                "\n 0 = no, 1 = yes"
-                "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(lightfreq,
-                "\n<50|60[,...]> Light frequency in Hz:"
-                "\n 50 for European and Asian lighting,"
-                " 60 for American lighting."
-                "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(bandingfilter,
-                "\n<0|1[,...]> Banding filter to reduce effects of"
-                " fluorescent lighting:"
-                "\n 0 disabled, 1 enabled."
-                "\nThis filter tries to reduce the pattern of horizontal"
-                "\nlight/dark bands caused by some (usually fluorescent)"
-                " lighting."
-                "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(clockdiv,
-                "\n<-1|n[,...]> "
-                "Force pixel clock divisor to a specific value (for experts):"
-                "\n  n may vary from 0 to 127."
-                "\n -1 for automatic value."
-                "\nSee also the 'double_buffer' module parameter."
-                "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(backlight,
-                "\n<0|1[,...]> Objects are lit from behind:"
-                "\n 0 = no, 1 = yes"
-                "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(mirror,
-                "\n<0|1[,...]> Reverse image horizontally:"
-                "\n 0 = no, 1 = yes"
-                "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(monochrome,
-                "\n<0|1[,...]> Use image sensor as monochrome sensor:"
-                "\n 0 = no, 1 = yes"
-                "\nNot all the sensors support monochrome color."
-                "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(brightness,
-                "\n<n[,...]> Set picture brightness (0-65535)."
-                "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
-                " for every device."
-                "\nThis parameter has no effect if 'autobright' is enabled."
-                "\n");
-MODULE_PARM_DESC(hue,
-                "\n<n[,...]> Set picture hue (0-65535)."
-                "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(colour,
-                "\n<n[,...]> Set picture saturation (0-65535)."
-                "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(contrast,
-                "\n<n[,...]> Set picture contrast (0-65535)."
-                "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
-                " for every device."
-                "\n");
-MODULE_PARM_DESC(whiteness,
-                "\n<n[,...]> Set picture whiteness (0-65535)."
-                "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
-                " for every device."
-                "\n");
-#ifdef W9968CF_DEBUG
-MODULE_PARM_DESC(debug,
-                "\n<n> Debugging information level, from 0 to 6:"
-                "\n0 = none (use carefully)"
-                "\n1 = critical errors"
-                "\n2 = significant informations"
-                "\n3 = configuration or general messages"
-                "\n4 = warnings"
-                "\n5 = called functions"
-                "\n6 = function internals"
-                "\nLevel 5 and 6 are useful for testing only, when only "
-                "one device is used."
-                "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
-                "\n");
-MODULE_PARM_DESC(specific_debug,
-                "\n<0|1> Enable or disable specific debugging messages:"
-                "\n0 = print messages concerning every level"
-                " <= 'debug' level."
-                "\n1 = print messages concerning the level"
-                " indicated by 'debug'."
-                "\nDefault value is "
-                __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
-                "\n");
-#endif /* W9968CF_DEBUG */
-
-
-
-/****************************************************************************
- * Some prototypes                                                          *
- ****************************************************************************/
-
-/* Video4linux interface */
-static const struct v4l2_file_operations w9968cf_fops;
-static int w9968cf_open(struct file *);
-static int w9968cf_release(struct file *);
-static int w9968cf_mmap(struct file *, struct vm_area_struct *);
-static long w9968cf_ioctl(struct file *, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *);
-static long w9968cf_v4l_ioctl(struct file *, unsigned int,
-                            void __user *);
-
-/* USB-specific */
-static int w9968cf_start_transfer(struct w9968cf_device*);
-static int w9968cf_stop_transfer(struct w9968cf_device*);
-static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
-static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
-static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
-static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
-static int w9968cf_read_sb(struct w9968cf_device*);
-static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb);
-
-/* Low-level I2C (SMBus) I/O */
-static int w9968cf_smbus_start(struct w9968cf_device*);
-static int w9968cf_smbus_stop(struct w9968cf_device*);
-static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
-static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
-static int w9968cf_smbus_write_ack(struct w9968cf_device*);
-static int w9968cf_smbus_read_ack(struct w9968cf_device*);
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
-static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-                                     u16 address, u8* value);
-static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address,
-                                          u8 subaddress, u8* value);
-static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
-                                      u16 address, u8 subaddress);
-static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
-                                               u16 address, u8 subaddress,
-                                               u8 value);
-
-/* I2C interface to kernel */
-static int w9968cf_i2c_init(struct w9968cf_device*);
-static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
-                                 unsigned short flags, char read_write,
-                                 u8 command, int size, union i2c_smbus_data*);
-static u32 w9968cf_i2c_func(struct i2c_adapter*);
-
-/* Memory management */
-static void* rvmalloc(unsigned long size);
-static void rvfree(void *mem, unsigned long size);
-static void w9968cf_deallocate_memory(struct w9968cf_device*);
-static int  w9968cf_allocate_memory(struct w9968cf_device*);
-
-/* High-level image sensor control functions */
-static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
-static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
-static int w9968cf_sensor_cmd(struct w9968cf_device*,
-                             unsigned int cmd, void *arg);
-static int w9968cf_sensor_init(struct w9968cf_device*);
-static int w9968cf_sensor_update_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*);
-static int w9968cf_sensor_update_picture(struct w9968cf_device*,
-                                        struct video_picture pict);
-
-/* Other helper functions */
-static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
-                                    enum w9968cf_model_id,
-                                    const unsigned short dev_nr);
-static void w9968cf_adjust_configuration(struct w9968cf_device*);
-static int w9968cf_turn_on_led(struct w9968cf_device*);
-static int w9968cf_init_chip(struct w9968cf_device*);
-static inline u16 w9968cf_valid_palette(u16 palette);
-static inline u16 w9968cf_valid_depth(u16 palette);
-static inline u8 w9968cf_need_decompression(u16 palette);
-static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
-static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
-static int w9968cf_postprocess_frame(struct w9968cf_device*,
-                                    struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
-static void w9968cf_init_framelist(struct w9968cf_device*);
-static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
-static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
-static void w9968cf_release_resources(struct w9968cf_device*);
-
-
-
-/****************************************************************************
- * Symbolic names                                                           *
- ****************************************************************************/
-
-/* Used to represent a list of values and their respective symbolic names */
-struct w9968cf_symbolic_list {
-       const int num;
-       const char *name;
-};
-
-/*--------------------------------------------------------------------------
-  Returns the name of the matching element in the symbolic_list array. The
-  end of the list must be marked with an element that has a NULL name.
-  --------------------------------------------------------------------------*/
-static inline const char *
-symbolic(struct w9968cf_symbolic_list list[], const int num)
-{
-       int i;
-
-       for (i = 0; list[i].name != NULL; i++)
-               if (list[i].num == num)
-                       return (list[i].name);
-
-       return "Unknown";
-}
-
-static struct w9968cf_symbolic_list camlist[] = {
-       { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
-       { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
-
-       /* Other cameras (having the same descriptors as Generic W996[87]CF) */
-       { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
-       { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
-       { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
-       { W9968CF_MOD_LL, "Lebon LDC-035A" },
-       { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
-       { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
-       { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
-       { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
-       { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
-
-       {  -1, NULL }
-};
-
-static struct w9968cf_symbolic_list senlist[] = {
-       { CC_OV76BE,   "OV76BE" },
-       { CC_OV7610,   "OV7610" },
-       { CC_OV7620,   "OV7620" },
-       { CC_OV7620AE, "OV7620AE" },
-       { CC_OV6620,   "OV6620" },
-       { CC_OV6630,   "OV6630" },
-       { CC_OV6630AE, "OV6630AE" },
-       { CC_OV6630AF, "OV6630AF" },
-       { -1, NULL }
-};
-
-/* Video4Linux1 palettes */
-static struct w9968cf_symbolic_list v4l1_plist[] = {
-       { VIDEO_PALETTE_GREY,    "GREY" },
-       { VIDEO_PALETTE_HI240,   "HI240" },
-       { VIDEO_PALETTE_RGB565,  "RGB565" },
-       { VIDEO_PALETTE_RGB24,   "RGB24" },
-       { VIDEO_PALETTE_RGB32,   "RGB32" },
-       { VIDEO_PALETTE_RGB555,  "RGB555" },
-       { VIDEO_PALETTE_YUV422,  "YUV422" },
-       { VIDEO_PALETTE_YUYV,    "YUYV" },
-       { VIDEO_PALETTE_UYVY,    "UYVY" },
-       { VIDEO_PALETTE_YUV420,  "YUV420" },
-       { VIDEO_PALETTE_YUV411,  "YUV411" },
-       { VIDEO_PALETTE_RAW,     "RAW" },
-       { VIDEO_PALETTE_YUV422P, "YUV422P" },
-       { VIDEO_PALETTE_YUV411P, "YUV411P" },
-       { VIDEO_PALETTE_YUV420P, "YUV420P" },
-       { VIDEO_PALETTE_YUV410P, "YUV410P" },
-       { -1, NULL }
-};
-
-/* Decoder error codes: */
-static struct w9968cf_symbolic_list decoder_errlist[] = {
-       { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
-       { W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
-       { W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },
-       { W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
-       { W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
-       { W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
-       { -1, NULL }
-};
-
-/* URB error codes: */
-static struct w9968cf_symbolic_list urb_errlist[] = {
-       { -ENOMEM,    "No memory for allocation of internal structures" },
-       { -ENOSPC,    "The host controller's bandwidth is already consumed" },
-       { -ENOENT,    "URB was canceled by unlink_urb" },
-       { -EXDEV,     "ISO transfer only partially completed" },
-       { -EAGAIN,    "Too match scheduled for the future" },
-       { -ENXIO,     "URB already queued" },
-       { -EFBIG,     "Too much ISO frames requested" },
-       { -ENOSR,     "Buffer error (overrun)" },
-       { -EPIPE,     "Specified endpoint is stalled (device not responding)"},
-       { -EOVERFLOW, "Babble (too much data)" },
-       { -EPROTO,    "Bit-stuff error (bad cable?)" },
-       { -EILSEQ,    "CRC/Timeout" },
-       { -ETIME,     "Device does not respond to token" },
-       { -ETIMEDOUT, "Device does not respond to command" },
-       { -1, NULL }
-};
-
-/****************************************************************************
- * Memory management functions                                              *
- ****************************************************************************/
-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);
-}
-
-
-/*--------------------------------------------------------------------------
-  Deallocate previously allocated memory.
-  --------------------------------------------------------------------------*/
-static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
-{
-       u8 i;
-
-       /* Free the isochronous transfer buffers */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               kfree(cam->transfer_buffer[i]);
-               cam->transfer_buffer[i] = NULL;
-       }
-
-       /* Free temporary frame buffer */
-       if (cam->frame_tmp.buffer) {
-               rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
-               cam->frame_tmp.buffer = NULL;
-       }
-
-       /* Free helper buffer */
-       if (cam->frame_vpp.buffer) {
-               rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
-               cam->frame_vpp.buffer = NULL;
-       }
-
-       /* Free video frame buffers */
-       if (cam->frame[0].buffer) {
-               rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
-               cam->frame[0].buffer = NULL;
-       }
-
-       cam->nbuffers = 0;
-
-       DBG(5, "Memory successfully deallocated")
-}
-
-
-/*--------------------------------------------------------------------------
-  Allocate memory buffers for USB transfers and video frames.
-  This function is called by open() only.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_allocate_memory(struct w9968cf_device* cam)
-{
-       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-       void* buff = NULL;
-       unsigned long hw_bufsize, vpp_bufsize;
-       u8 i, bpp;
-
-       /* NOTE: Deallocation is done elsewhere in case of error */
-
-       /* Calculate the max amount of raw data per frame from the device */
-       hw_bufsize = cam->maxwidth*cam->maxheight*2;
-
-       /* Calculate the max buf. size needed for post-processing routines */
-       bpp = (w9968cf_vpp) ? 4 : 2;
-       if (cam->upscaling)
-               vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
-                                 cam->maxwidth*cam->maxheight*bpp);
-       else
-               vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
-
-       /* Allocate memory for the isochronous transfer buffers */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               if (!(cam->transfer_buffer[i] =
-                     kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
-                       DBG(1, "Couldn't allocate memory for the isochronous "
-                              "transfer buffers (%u bytes)",
-                           p_size * W9968CF_ISO_PACKETS)
-                       return -ENOMEM;
-               }
-       }
-
-       /* Allocate memory for the temporary frame buffer */
-       if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
-               DBG(1, "Couldn't allocate memory for the temporary "
-                      "video frame buffer (%lu bytes)", hw_bufsize)
-               return -ENOMEM;
-       }
-       cam->frame_tmp.size = hw_bufsize;
-       cam->frame_tmp.number = -1;
-
-       /* Allocate memory for the helper buffer */
-       if (w9968cf_vpp) {
-               if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
-                       DBG(1, "Couldn't allocate memory for the helper buffer"
-                              " (%lu bytes)", vpp_bufsize)
-                       return -ENOMEM;
-               }
-               cam->frame_vpp.size = vpp_bufsize;
-       } else
-               cam->frame_vpp.buffer = NULL;
-
-       /* Allocate memory for video frame buffers */
-       cam->nbuffers = cam->max_buffers;
-       while (cam->nbuffers >= 2) {
-               if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
-                       break;
-               else
-                       cam->nbuffers--;
-       }
-
-       if (!buff) {
-               DBG(1, "Couldn't allocate memory for the video frame buffers")
-               cam->nbuffers = 0;
-               return -ENOMEM;
-       }
-
-       if (cam->nbuffers != cam->max_buffers)
-               DBG(2, "Couldn't allocate memory for %u video frame buffers. "
-                      "Only memory for %u buffers has been allocated",
-                   cam->max_buffers, cam->nbuffers)
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].buffer = buff + i*vpp_bufsize;
-               cam->frame[i].size = vpp_bufsize;
-               cam->frame[i].number = i;
-               /* Circular list */
-               if (i != cam->nbuffers-1)
-                       cam->frame[i].next = &cam->frame[i+1];
-               else
-                       cam->frame[i].next = &cam->frame[0];
-               cam->frame[i].status = F_UNUSED;
-       }
-
-       DBG(5, "Memory successfully allocated")
-       return 0;
-}
-
-
-
-/****************************************************************************
- * USB-specific functions                                                   *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This is an handler function which is called after the URBs are completed.
-  It collects multiple data packets coming from the camera by putting them
-  into frame buffers: one or more zero data length data packets are used to
-  mark the end of a video frame; the first non-zero data packet is the start
-  of the next video frame; if an error is encountered in a packet, the entire
-  video frame is discarded and grabbed again.
-  If there are no requested frames in the FIFO list, packets are collected into
-  a temporary buffer.
-  --------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb)
-{
-       struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
-       struct w9968cf_frame_t** f;
-       unsigned int len, status;
-       void* pos;
-       u8 i;
-       int err = 0;
-
-       if ((!cam->streaming) || cam->disconnected) {
-               DBG(4, "Got interrupt, but not streaming")
-               return;
-       }
-
-       /* "(*f)" will be used instead of "cam->frame_current" */
-       f = &cam->frame_current;
-
-       /* If a frame has been requested and we are grabbing into
-          the temporary frame, we'll switch to that requested frame */
-       if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
-               if (cam->frame_tmp.status == F_GRABBING) {
-                       w9968cf_pop_frame(cam, &cam->frame_current);
-                       (*f)->status = F_GRABBING;
-                       (*f)->length = cam->frame_tmp.length;
-                       memcpy((*f)->buffer, cam->frame_tmp.buffer,
-                              (*f)->length);
-                       DBG(6, "Switched from temp. frame to frame #%d",
-                           (*f)->number)
-               }
-       }
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status && len != 0) {
-                       DBG(4, "URB failed, error in data packet "
-                              "(error #%u, %s)",
-                           status, symbolic(urb_errlist, status))
-                       (*f)->status = F_ERROR;
-                       continue;
-               }
-
-               if (len) { /* start of frame */
-
-                       if ((*f)->status == F_UNUSED) {
-                               (*f)->status = F_GRABBING;
-                               (*f)->length = 0;
-                       }
-
-                       /* Buffer overflows shouldn't happen, however...*/
-                       if ((*f)->length + len > (*f)->size) {
-                               DBG(4, "Buffer overflow: bad data packets")
-                               (*f)->status = F_ERROR;
-                       }
-
-                       if ((*f)->status == F_GRABBING) {
-                               memcpy((*f)->buffer + (*f)->length, pos, len);
-                               (*f)->length += len;
-                       }
-
-               } else if ((*f)->status == F_GRABBING) { /* end of frame */
-
-                       DBG(6, "Frame #%d successfully grabbed", (*f)->number)
-
-                       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-                               err = w9968cf_vpp->check_headers((*f)->buffer,
-                                                                (*f)->length);
-                               if (err) {
-                                       DBG(4, "Skip corrupted frame: %s",
-                                           symbolic(decoder_errlist, err))
-                                       (*f)->status = F_UNUSED;
-                                       continue; /* grab this frame again */
-                               }
-                       }
-
-                       (*f)->status = F_READY;
-                       (*f)->queued = 0;
-
-                       /* Take a pointer to the new frame from the FIFO list.
-                          If the list is empty,we'll use the temporary frame*/
-                       if (*cam->requested_frame)
-                               w9968cf_pop_frame(cam, &cam->frame_current);
-                       else {
-                               cam->frame_current = &cam->frame_tmp;
-                               (*f)->status = F_UNUSED;
-                       }
-
-               } else if ((*f)->status == F_ERROR)
-                       (*f)->status = F_UNUSED; /* grab it again */
-
-               PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
-                     (unsigned long)(*f)->length, i, len, (*f)->status)
-
-       } /* end for */
-
-       /* Resubmit this URB */
-       urb->dev = cam->usbdev;
-       urb->status = 0;
-       spin_lock(&cam->urb_lock);
-       if (cam->streaming)
-               if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
-                       cam->misconfigured = 1;
-                       DBG(1, "Couldn't resubmit the URB: error %d, %s",
-                           err, symbolic(urb_errlist, err))
-               }
-       spin_unlock(&cam->urb_lock);
-
-       /* Wake up the user process */
-       wake_up_interruptible(&cam->wait_queue);
-}
-
-
-/*---------------------------------------------------------------------------
-  Setup the URB structures for the isochronous transfer.
-  Submit the URBs so that the data transfer begins.
-  Return 0 on success, a negative number otherwise.
-  ---------------------------------------------------------------------------*/
-static int w9968cf_start_transfer(struct w9968cf_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-       u16 w, h, d;
-       int vidcapt;
-       u32 t_size;
-       int err = 0;
-       s8 i, j;
-
-       for (i = 0; i < W9968CF_URBS; i++) {
-               urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
-               if (!urb) {
-                       for (j = 0; j < i; j++)
-                               usb_free_urb(cam->urb[j]);
-                       DBG(1, "Couldn't allocate the URB structures")
-                       return -ENOMEM;
-               }
-
-               cam->urb[i] = urb;
-               urb->dev = udev;
-               urb->context = (void*)cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = W9968CF_ISO_PACKETS;
-               urb->complete = w9968cf_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = p_size*j;
-                       urb->iso_frame_desc[j].length = p_size;
-               }
-       }
-
-       /* Transfer size per frame, in WORD ! */
-       d = cam->hw_depth;
-       w = cam->hw_width;
-       h = cam->hw_height;
-
-       t_size = (w*h*d)/16;
-
-       err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-
-       /* Transfer size */
-       err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
-       err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION)
-               err += w9968cf_upload_quantizationtables(cam);
-
-       vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
-       err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
-
-       err += usb_set_interface(udev, 0, cam->altsetting);
-       err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
-
-       if (err || (vidcapt < 0)) {
-               for (i = 0; i < W9968CF_URBS; i++)
-                       usb_free_urb(cam->urb[i]);
-               DBG(1, "Couldn't tell the camera to start the data transfer")
-               return err;
-       }
-
-       w9968cf_init_framelist(cam);
-
-       /* Begin to grab into the temporary buffer */
-       cam->frame_tmp.status = F_UNUSED;
-       cam->frame_tmp.queued = 0;
-       cam->frame_current = &cam->frame_tmp;
-
-       if (!(cam->vpp_flag & VPP_DECOMPRESSION))
-               DBG(5, "Isochronous transfer size: %lu bytes/frame",
-                   (unsigned long)t_size*2)
-
-       DBG(5, "Starting the isochronous transfer...")
-
-       cam->streaming = 1;
-
-       /* Submit the URBs */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       cam->streaming = 0;
-                       for (j = i-1; j >= 0; j--) {
-                               usb_kill_urb(cam->urb[j]);
-                               usb_free_urb(cam->urb[j]);
-                       }
-                       DBG(1, "Couldn't send a transfer request to the "
-                              "USB core (error #%d, %s)", err,
-                           symbolic(urb_errlist, err))
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_stop_transfer(struct w9968cf_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       unsigned long lock_flags;
-       int err = 0;
-       s8 i;
-
-       if (!cam->streaming)
-               return 0;
-
-       /* This avoids race conditions with usb_submit_urb()
-          in the URB completition handler */
-       spin_lock_irqsave(&cam->urb_lock, lock_flags);
-       cam->streaming = 0;
-       spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
-
-       for (i = W9968CF_URBS-1; i >= 0; i--)
-               if (cam->urb[i]) {
-                       usb_kill_urb(cam->urb[i]);
-                       usb_free_urb(cam->urb[i]);
-                       cam->urb[i] = NULL;
-               }
-
-       if (cam->disconnected)
-               goto exit;
-
-       err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
-       err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
-       err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
-
-       if (err) {
-               DBG(2, "Failed to tell the camera to stop the isochronous "
-                      "transfer. However this is not a critical error.")
-               return -EIO;
-       }
-
-exit:
-       DBG(5, "Isochronous transfer stopped")
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write a W9968CF register.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       int res;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-                             value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to write a register "
-                      "(value 0x%04X, index 0x%02X, error #%d, %s)",
-                   value, index, res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read a W9968CF register.
-  Return the register value on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u16* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
-                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to read a register "
-                      "(index 0x%02X, error #%d, %s)",
-                   index, res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write 64-bit data to the fast serial bus registers.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
-{
-       struct usb_device* udev = cam->usbdev;
-       u16 value;
-       int res;
-
-       value = *data++;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-                             value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to write the FSB registers "
-                      "(error #%d, %s)", res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write data to the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
-{
-       int err = 0;
-
-       err = w9968cf_write_reg(cam, value, 0x01);
-       udelay(W9968CF_I2C_BUS_DELAY);
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read data from the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_sb(struct w9968cf_device* cam)
-{
-       int v = 0;
-
-       v = w9968cf_read_reg(cam, 0x01);
-       udelay(W9968CF_I2C_BUS_DELAY);
-
-       return v;
-}
-
-
-/*--------------------------------------------------------------------------
-  Upload quantization tables for the JPEG compression.
-  This function is called by w9968cf_start_transfer().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
-{
-       u16 a, b;
-       int err = 0, i, j;
-
-       err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
-
-       for (i = 0, j = 0; i < 32; i++, j += 2) {
-               a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
-               b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
-               err += w9968cf_write_reg(cam, a, 0x40+i);
-               err += w9968cf_write_reg(cam, b, 0x60+i);
-       }
-       err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
-
-       return err;
-}
-
-
-
-/****************************************************************************
- * Low-level I2C I/O functions.                                             *
- * The adapter supports the following I2C transfer functions:               *
- * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
- * i2c_adap_read_byte_data()                                                *
- * i2c_adap_read_byte()                                                     *
- ****************************************************************************/
-
-static int w9968cf_smbus_start(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_stop(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
-{
-       u8 bit;
-       int err = 0, sda;
-
-       for (bit = 0 ; bit < 8 ; bit++) {
-               sda = (v & 0x80) ? 2 : 0;
-               v <<= 1;
-               /* SDE=1, SDA=sda, SCL=0 */
-               err += w9968cf_write_sb(cam, 0x10 | sda);
-               /* SDE=1, SDA=sda, SCL=1 */
-               err += w9968cf_write_sb(cam, 0x11 | sda);
-               /* SDE=1, SDA=sda, SCL=0 */
-               err += w9968cf_write_sb(cam, 0x10 | sda);
-       }
-
-       return err;
-}
-
-
-static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
-{
-       u8 bit;
-       int err = 0;
-
-       *v = 0;
-       for (bit = 0 ; bit < 8 ; bit++) {
-               *v <<= 1;
-               err += w9968cf_write_sb(cam, 0x0013);
-               *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
-               err += w9968cf_write_sb(cam, 0x0012);
-       }
-
-       return err;
-}
-
-
-static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
-{
-       int err = 0, sda;
-
-       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-       sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
-       err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
-       if (sda < 0)
-               err += sda;
-       if (sda == 1) {
-               DBG(6, "Couldn't receive the ACK")
-               err += -1;
-       }
-
-       return err;
-}
-
-
-/* This seems to refresh the communication through the serial bus */
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
-{
-       int err = 0, j;
-
-       for (j = 1; j <= 10; j++) {
-               err = w9968cf_write_reg(cam, 0x0020, 0x01);
-               err += w9968cf_write_reg(cam, 0x0000, 0x01);
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
-                                    u16 address, u8 subaddress,u8 value)
-{
-       u16* data = cam->data_buffer;
-       int err = 0;
-
-       err += w9968cf_smbus_refresh_bus(cam);
-
-       /* Enable SBUS outputs */
-       err += w9968cf_write_sb(cam, 0x0020);
-
-       data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
-       data[0] |= (address & 0x40) ? 0x4000 : 0x0;
-       data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
-       data[1] |= (address & 0x20) ? 0x0150 : 0x0;
-       data[1] |= (address & 0x10) ? 0x5400 : 0x0;
-       data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
-       data[2] |= (address & 0x04) ? 0x0540 : 0x0;
-       data[2] |= (address & 0x02) ? 0x5000 : 0x0;
-       data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
-       data[3] |= (address & 0x01) ? 0x0054 : 0x0;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
-       data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
-       data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
-       data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
-       data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
-       data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
-       data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
-       data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
-       data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
-       data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
-       data[3] = 0x001d;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
-       data[0] |= (value & 0x40) ? 0x0540 : 0x0;
-       data[0] |= (value & 0x20) ? 0x5000 : 0x0;
-       data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
-       data[1] |= (value & 0x10) ? 0x0054 : 0x0;
-       data[1] |= (value & 0x08) ? 0x1500 : 0x0;
-       data[1] |= (value & 0x04) ? 0x4000 : 0x0;
-       data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
-       data[2] |= (value & 0x02) ? 0x0150 : 0x0;
-       data[2] |= (value & 0x01) ? 0x5400 : 0x0;
-       data[3] = 0xfe1d;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       /* Disable SBUS outputs */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
-                      "value 0x%02X", address, subaddress, value)
-       else
-               DBG(5, "I2C write byte data failed, addr.0x%04X, "
-                      "subaddr.0x%02X, value 0x%02X",
-                   address, subaddress, value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam,
-                               u16 address, u8 subaddress,
-                               u8* value)
-{
-       int err = 0;
-
-       /* Serial data enable */
-       err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
-
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_write_byte(cam, subaddress);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address + 1);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_read_byte(cam, value);
-       err += w9968cf_smbus_write_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-
-       /* Serial data disable */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C read byte data done, addr.0x%04X, "
-                      "subaddr.0x%02X, value 0x%02X",
-                   address, subaddress, *value)
-       else
-               DBG(5, "I2C read byte data failed, addr.0x%04X, "
-                      "subaddr.0x%02X, wrong value 0x%02X",
-                   address, subaddress, *value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-                          u16 address, u8* value)
-{
-       int err = 0;
-
-       /* Serial data enable */
-       err += w9968cf_write_sb(cam, 0x0013);
-
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address + 1);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_read_byte(cam, value);
-       err += w9968cf_smbus_write_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-
-       /* Serial data disable */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C read byte done, addr.0x%04X, "
-                      "value 0x%02X", address, *value)
-       else
-               DBG(5, "I2C read byte failed, addr.0x%04X, "
-                      "wrong value 0x%02X", address, *value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
-                           u16 address, u8 value)
-{
-       DBG(4, "i2c_write_byte() is an unsupported transfer mode")
-       return -EINVAL;
-}
-
-
-
-/****************************************************************************
- * I2C interface to kernel                                                  *
- ****************************************************************************/
-
-static int
-w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
-                      unsigned short flags, char read_write, u8 command,
-                      int size, union i2c_smbus_data *data)
-{
-       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
-       struct w9968cf_device *cam = to_cam(v4l2_dev);
-       u8 i;
-       int err = 0;
-
-       if (size == I2C_SMBUS_BYTE) {
-               /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
-               addr <<= 1;
-
-               if (read_write == I2C_SMBUS_WRITE)
-                       err = w9968cf_i2c_adap_write_byte(cam, addr, command);
-               else if (read_write == I2C_SMBUS_READ)
-                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-                               err = w9968cf_i2c_adap_read_byte(cam, addr,
-                                                        &data->byte);
-                               if (err) {
-                                       if (w9968cf_smbus_refresh_bus(cam)) {
-                                               err = -EIO;
-                                               break;
-                                       }
-                               } else
-                                       break;
-                       }
-       } else if (size == I2C_SMBUS_BYTE_DATA) {
-               addr <<= 1;
-
-               if (read_write == I2C_SMBUS_WRITE)
-                       err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
-                                                         command, data->byte);
-               else if (read_write == I2C_SMBUS_READ) {
-                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-                               err = w9968cf_i2c_adap_read_byte_data(cam,addr,
-                                                        command, &data->byte);
-                               if (err) {
-                                       if (w9968cf_smbus_refresh_bus(cam)) {
-                                               err = -EIO;
-                                               break;
-                                       }
-                               } else
-                                       break;
-                       }
-
-               } else
-                       return -EINVAL;
-
-       } else {
-               DBG(4, "Unsupported I2C transfer mode (%d)", size)
-               return -EINVAL;
-       }
-       return err;
-}
-
-
-static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
-{
-       return I2C_FUNC_SMBUS_READ_BYTE |
-              I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_init(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       static struct i2c_algorithm algo = {
-               .smbus_xfer =    w9968cf_i2c_smbus_xfer,
-               .functionality = w9968cf_i2c_func,
-       };
-
-       static struct i2c_adapter adap = {
-               .owner =             THIS_MODULE,
-               .algo =              &algo,
-       };
-
-       memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
-       strcpy(cam->i2c_adapter.name, "w9968cf");
-       cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
-       i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
-
-       DBG(6, "Registering I2C adapter with kernel...")
-
-       err = i2c_add_adapter(&cam->i2c_adapter);
-       if (err)
-               DBG(1, "Failed to register the I2C adapter")
-       else
-               DBG(5, "I2C adapter registered")
-
-       return err;
-}
-
-
-
-/****************************************************************************
- * Helper functions                                                         *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  Turn on the LED on some webcams. A beep should be heard too.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_turn_on_led(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
-       err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
-       err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
-       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
-
-       if (err)
-               DBG(2, "Couldn't turn on the LED")
-
-       DBG(5, "LED turned on")
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write some registers for the device initialization.
-  This function is called once on open().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_init_chip(struct w9968cf_device* cam)
-{
-       unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
-                     y0 = 0x0000,
-                     u0 = y0 + hw_bufsize/2,
-                     v0 = u0 + hw_bufsize/4,
-                     y1 = v0 + hw_bufsize/4,
-                     u1 = y1 + hw_bufsize/2,
-                     v1 = u1 + hw_bufsize/4;
-       int err = 0;
-
-       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
-
-       err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
-       err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
-
-       err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
-       err += w9968cf_write_reg(cam, y0 >> 16, 0x21);    /* Y buf.0, high */
-       err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
-       err += w9968cf_write_reg(cam, u0 >> 16, 0x25);    /* U buf.0, high */
-       err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
-       err += w9968cf_write_reg(cam, v0 >> 16, 0x29);    /* V buf.0, high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x23);    /* Y buf.1, high */
-       err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
-       err += w9968cf_write_reg(cam, u1 >> 16, 0x27);    /* U buf.1, high */
-       err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
-       err += w9968cf_write_reg(cam, v1 >> 16, 0x2b);    /* V buf.1, high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x33);    /* JPEG buf 0 high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x35);    /* JPEG bug 1 high */
-
-       err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
-       err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
-       err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
-       err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
-
-       err += w9968cf_set_picture(cam, cam->picture); /* this before */
-       err += w9968cf_set_window(cam, cam->window);
-
-       if (err)
-               DBG(1, "Chip initialization failed")
-       else
-               DBG(5, "Chip successfully initialized")
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the palette is supported, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_palette(u16 palette)
-{
-       u8 i = 0;
-       while (w9968cf_formatlist[i].palette != 0) {
-               if (palette == w9968cf_formatlist[i].palette)
-                       return palette;
-               i++;
-       }
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return the depth corresponding to the given palette.
-  Palette _must_ be supported !
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_depth(u16 palette)
-{
-       u8 i=0;
-       while (w9968cf_formatlist[i].palette != palette)
-               i++;
-
-       return w9968cf_formatlist[i].depth;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the format requires decompression, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u8 w9968cf_need_decompression(u16 palette)
-{
-       u8 i = 0;
-       while (w9968cf_formatlist[i].palette != 0) {
-               if (palette == w9968cf_formatlist[i].palette)
-                       return w9968cf_formatlist[i].compression;
-               i++;
-       }
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the picture settings of the camera.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
-{
-       u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
-       int err = 0;
-
-       /* Make sure we are using a valid depth */
-       pict.depth = w9968cf_valid_depth(pict.palette);
-
-       fmt = pict.palette;
-
-       hw_depth = pict.depth; /* depth used by the winbond chip */
-       hw_palette = pict.palette; /* palette used by the winbond chip */
-
-       /* VS & HS polarities */
-       reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
-
-       switch (fmt)
-       {
-               case VIDEO_PALETTE_UYVY:
-                       reg_v |= 0x0000;
-                       cam->vpp_flag = VPP_NONE;
-                       break;
-               case VIDEO_PALETTE_YUV422P:
-                       reg_v |= 0x0002;
-                       cam->vpp_flag = VPP_DECOMPRESSION;
-                       break;
-               case VIDEO_PALETTE_YUV420:
-               case VIDEO_PALETTE_YUV420P:
-                       reg_v |= 0x0003;
-                       cam->vpp_flag = VPP_DECOMPRESSION;
-                       break;
-               case VIDEO_PALETTE_YUYV:
-               case VIDEO_PALETTE_YUV422:
-                       reg_v |= 0x0000;
-                       cam->vpp_flag = VPP_SWAP_YUV_BYTES;
-                       hw_palette = VIDEO_PALETTE_UYVY;
-                       break;
-               /* Original video is used instead of RGBX palettes.
-                  Software conversion later. */
-               case VIDEO_PALETTE_GREY:
-               case VIDEO_PALETTE_RGB555:
-               case VIDEO_PALETTE_RGB565:
-               case VIDEO_PALETTE_RGB24:
-               case VIDEO_PALETTE_RGB32:
-                       reg_v |= 0x0000; /* UYVY 16 bit is used */
-                       hw_depth = 16;
-                       hw_palette = VIDEO_PALETTE_UYVY;
-                       cam->vpp_flag = VPP_UYVY_TO_RGBX;
-                       break;
-       }
-
-       /* NOTE: due to memory issues, it is better to disable the hardware
-                double buffering during compression */
-       if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
-               reg_v |= 0x0080;
-
-       if (cam->clamping)
-               reg_v |= 0x0020;
-
-       if (cam->filter_type == 1)
-               reg_v |= 0x0008;
-       else if (cam->filter_type == 2)
-               reg_v |= 0x000c;
-
-       if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
-               goto error;
-
-       if ((err = w9968cf_sensor_update_picture(cam, pict)))
-               goto error;
-
-       /* If all went well, update the device data structure */
-       memcpy(&cam->picture, &pict, sizeof(pict));
-       cam->hw_depth = hw_depth;
-       cam->hw_palette = hw_palette;
-
-       /* Settings changed, so we clear the frame buffers */
-       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-       DBG(4, "Palette is %s, depth is %u bpp",
-           symbolic(v4l1_plist, pict.palette), pict.depth)
-
-       return 0;
-
-error:
-       DBG(1, "Failed to change picture settings")
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the capture area size of the camera.
-  This function _must_ be called _after_ w9968cf_set_picture().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
-{
-       u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
-       unsigned long fw, fh;
-       struct ovcamchip_window s_win;
-       int err = 0;
-
-       /* Work around to avoid FP arithmetics */
-       #define SC(x) ((x) << 10)
-       #define UNSC(x) ((x) >> 10)
-
-       /* Make sure we are using a supported resolution */
-       if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
-               goto error;
-
-       /* Scaling factors */
-       fw = SC(win.width) / cam->maxwidth;
-       fh = SC(win.height) / cam->maxheight;
-
-       /* Set up the width and height values used by the chip */
-       if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
-               cam->vpp_flag |= VPP_UPSCALE;
-               /* Calculate largest w,h mantaining the same w/h ratio */
-               w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
-               h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
-               if (w < cam->minwidth) /* just in case */
-                       w = cam->minwidth;
-               if (h < cam->minheight) /* just in case */
-                       h = cam->minheight;
-       } else {
-               cam->vpp_flag &= ~VPP_UPSCALE;
-               w = win.width;
-               h = win.height;
-       }
-
-       /* x,y offsets of the cropped area */
-       scx = cam->start_cropx;
-       scy = cam->start_cropy;
-
-       /* Calculate cropped area manteining the right w/h ratio */
-       if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
-               cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
-               ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
-       } else {
-               cw = w;
-               ch = h;
-       }
-
-       /* Setup the window of the sensor */
-       s_win.format = VIDEO_PALETTE_UYVY;
-       s_win.width = cam->maxwidth;
-       s_win.height = cam->maxheight;
-       s_win.quarter = 0; /* full progressive video */
-
-       /* Center it */
-       s_win.x = (s_win.width - cw) / 2;
-       s_win.y = (s_win.height - ch) / 2;
-
-       /* Clock divisor */
-       if (cam->clockdiv >= 0)
-               s_win.clockdiv = cam->clockdiv; /* manual override */
-       else
-               switch (cam->sensor) {
-                       case CC_OV6620:
-                               s_win.clockdiv = 0;
-                               break;
-                       case CC_OV6630:
-                               s_win.clockdiv = 0;
-                               break;
-                       case CC_OV76BE:
-                       case CC_OV7610:
-                       case CC_OV7620:
-                               s_win.clockdiv = 0;
-                               break;
-                       default:
-                               s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
-               }
-
-       /* We have to scale win.x and win.y offsets */
-       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-            || (cam->vpp_flag & VPP_UPSCALE) ) {
-               ax = SC(win.x)/fw;
-               ay = SC(win.y)/fh;
-       } else {
-               ax = win.x;
-               ay = win.y;
-       }
-
-       if ((ax + cw) > cam->maxwidth)
-               ax = cam->maxwidth - cw;
-
-       if ((ay + ch) > cam->maxheight)
-               ay = cam->maxheight - ch;
-
-       /* Adjust win.x, win.y */
-       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-            || (cam->vpp_flag & VPP_UPSCALE) ) {
-               win.x = UNSC(ax*fw);
-               win.y = UNSC(ay*fh);
-       } else {
-               win.x = ax;
-               win.y = ay;
-       }
-
-       /* Offsets used by the chip */
-       x = ax + s_win.x;
-       y = ay + s_win.y;
-
-       /* Go ! */
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
-               goto error;
-
-       err += w9968cf_write_reg(cam, scx + x, 0x10);
-       err += w9968cf_write_reg(cam, scy + y, 0x11);
-       err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
-       err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
-       err += w9968cf_write_reg(cam, w, 0x14);
-       err += w9968cf_write_reg(cam, h, 0x15);
-
-       /* JPEG width & height */
-       err += w9968cf_write_reg(cam, w, 0x30);
-       err += w9968cf_write_reg(cam, h, 0x31);
-
-       /* Y & UV frame buffer strides (in WORD) */
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               err += w9968cf_write_reg(cam, w/2, 0x2c);
-               err += w9968cf_write_reg(cam, w/4, 0x2d);
-       } else
-               err += w9968cf_write_reg(cam, w, 0x2c);
-
-       if (err)
-               goto error;
-
-       /* If all went well, update the device data structure */
-       memcpy(&cam->window, &win, sizeof(win));
-       cam->hw_width = w;
-       cam->hw_height = h;
-
-       /* Settings changed, so we clear the frame buffers */
-       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-       DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)",
-           win.width, win.height, win.x, win.y)
-
-       PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
-             "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
-             x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
-             win.width, win.height)
-
-       return 0;
-
-error:
-       DBG(1, "Failed to change the capture area size")
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Adjust the asked values for window width and height.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
-{
-       unsigned int maxw, maxh, align;
-
-       maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-              w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
-                          : cam->maxwidth;
-       maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-              w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-                          : cam->maxheight;
-       align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
-
-       v4l_bound_align_image(width, cam->minwidth, maxw, align,
-                             height, cam->minheight, maxh, align, 0);
-
-       PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Initialize the FIFO list of requested frames.
-  --------------------------------------------------------------------------*/
-static void w9968cf_init_framelist(struct w9968cf_device* cam)
-{
-       u8 i;
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->requested_frame[i] = NULL;
-               cam->frame[i].queued = 0;
-               cam->frame[i].status = F_UNUSED;
-       }
-}
-
-
-/*--------------------------------------------------------------------------
-  Add a frame in the FIFO list of requested frames.
-  This function is called in process context.
-  --------------------------------------------------------------------------*/
-static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
-{
-       u8 f;
-       unsigned long lock_flags;
-
-       spin_lock_irqsave(&cam->flist_lock, lock_flags);
-
-       for (f=0; cam->requested_frame[f] != NULL; f++);
-       cam->requested_frame[f] = &cam->frame[f_num];
-       cam->frame[f_num].queued = 1;
-       cam->frame[f_num].status = F_UNUSED; /* clear the status */
-
-       spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
-
-       DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
-}
-
-
-/*--------------------------------------------------------------------------
-  Read, store and remove the first pointer in the FIFO list of requested
-  frames. This function is called in interrupt context.
-  --------------------------------------------------------------------------*/
-static void
-w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
-{
-       u8 i;
-
-       spin_lock(&cam->flist_lock);
-
-       *framep = cam->requested_frame[0];
-
-       /* Shift the list of pointers */
-       for (i = 0; i < cam->nbuffers-1; i++)
-               cam->requested_frame[i] = cam->requested_frame[i+1];
-       cam->requested_frame[i] = NULL;
-
-       spin_unlock(&cam->flist_lock);
-
-       DBG(6,"Popped frame #%d from the list", (*framep)->number)
-}
-
-
-/*--------------------------------------------------------------------------
-  High-level video post-processing routine on grabbed frames.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_postprocess_frame(struct w9968cf_device* cam,
-                         struct w9968cf_frame_t* fr)
-{
-       void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
-       u16 w = cam->window.width,
-           h = cam->window.height,
-           d = cam->picture.depth,
-           fmt = cam->picture.palette,
-           rgb = cam->force_rgb,
-           hw_w = cam->hw_width,
-           hw_h = cam->hw_height,
-           hw_d = cam->hw_depth;
-       int err = 0;
-
-       #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               memcpy(pOut, pIn, fr->length);
-               _PSWAP(pIn, pOut)
-               err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
-               PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
-               fr->length = (hw_w*hw_h*hw_d)/8;
-               _PSWAP(pIn, pOut)
-               if (err) {
-                       DBG(4, "An error occurred while decoding the frame: "
-                              "%s", symbolic(decoder_errlist, err))
-                       return err;
-               } else
-                       DBG(6, "Frame decoded")
-       }
-
-       if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
-               w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
-               DBG(6, "Original UYVY component ordering changed")
-       }
-
-       if (cam->vpp_flag & VPP_UPSCALE) {
-               w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
-               fr->length = (w*h*hw_d)/8;
-               _PSWAP(pIn, pOut)
-               DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
-                   hw_w, hw_h, hw_d, w, h)
-       }
-
-       if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
-               w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
-               fr->length = (w*h*d)/8;
-               _PSWAP(pIn, pOut)
-               DBG(6, "UYVY-16bit to %s conversion done",
-                   symbolic(v4l1_plist, fmt))
-       }
-
-       if (pOut == fr->buffer)
-               memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
-
-       return 0;
-}
-
-
-
-/****************************************************************************
- * Image sensor control routines                                            *
- ****************************************************************************/
-
-static int
-w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
-{
-       struct ovcamchip_control ctl;
-       int err;
-
-       ctl.id = cid;
-       ctl.value = val;
-
-       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
-
-       return err;
-}
-
-
-static int
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
-{
-       struct ovcamchip_control ctl;
-       int err;
-
-       ctl.id = cid;
-
-       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
-       if (!err)
-               *val = ctl.value;
-
-       return err;
-}
-
-
-static int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
-{
-       int rc;
-
-       rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
-       /* The I2C driver returns -EPERM on non-supported controls */
-       return (rc < 0 && rc != -EPERM) ? rc : 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update some settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       /* Auto brightness */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT,
-                                        cam->auto_brt);
-       if (err)
-               return err;
-
-       /* Auto exposure */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP,
-                                        cam->auto_exp);
-       if (err)
-               return err;
-
-       /* Banding filter */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT,
-                                        cam->bandfilt);
-       if (err)
-               return err;
-
-       /* Light frequency */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
-                                        cam->lightfreq);
-       if (err)
-               return err;
-
-       /* Back light */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
-                                        cam->backlight);
-       if (err)
-               return err;
-
-       /* Mirror */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
-                                        cam->mirror);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Get some current picture settings from the image sensor and update the
-  internal 'picture' structure of the camera.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
-{
-       int err, v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
-       if (err)
-               return err;
-       cam->picture.contrast = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
-       if (err)
-               return err;
-       cam->picture.brightness = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
-       if (err)
-               return err;
-       cam->picture.colour = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
-       if (err)
-               return err;
-       cam->picture.hue = v;
-
-       DBG(5, "Got picture settings from the image sensor")
-
-       PDBGG("Brightness, contrast, hue, colour, whiteness are "
-             "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
-             cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update picture settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_update_picture(struct w9968cf_device* cam,
-                             struct video_picture pict)
-{
-       int err = 0;
-
-       if ((!cam->sensor_initialized)
-           || pict.contrast != cam->picture.contrast) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
-                                                pict.contrast);
-               if (err)
-                       goto fail;
-               DBG(4, "Contrast changed from %u to %u",
-                   cam->picture.contrast, pict.contrast)
-               cam->picture.contrast = pict.contrast;
-       }
-
-       if (((!cam->sensor_initialized) ||
-           pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT,
-                                                pict.brightness);
-               if (err)
-                       goto fail;
-               DBG(4, "Brightness changed from %u to %u",
-                   cam->picture.brightness, pict.brightness)
-               cam->picture.brightness = pict.brightness;
-       }
-
-       if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT,
-                                                pict.colour);
-               if (err)
-                       goto fail;
-               DBG(4, "Colour changed from %u to %u",
-                   cam->picture.colour, pict.colour)
-               cam->picture.colour = pict.colour;
-       }
-
-       if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE,
-                                                pict.hue);
-               if (err)
-                       goto fail;
-               DBG(4, "Hue changed from %u to %u",
-                   cam->picture.hue, pict.hue)
-               cam->picture.hue = pict.hue;
-       }
-
-       return 0;
-
-fail:
-       DBG(4, "Failed to change sensor picture setting")
-       return err;
-}
-
-
-
-/****************************************************************************
- * Camera configuration                                                     *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This function is called when a supported image sensor is detected.
-  Return 0 if the initialization succeeds, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_init(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE,
-                                     &cam->monochrome)))
-               goto error;
-
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE,
-                                     &cam->sensor)))
-               goto error;
-
-       /* NOTE: Make sure width and height are a multiple of 16 */
-       switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
-               case OV6xx0_SID:
-                       cam->maxwidth = 352;
-                       cam->maxheight = 288;
-                       cam->minwidth = 64;
-                       cam->minheight = 48;
-                       break;
-               case OV7xx0_SID:
-                       cam->maxwidth = 640;
-                       cam->maxheight = 480;
-                       cam->minwidth = 64;
-                       cam->minheight = 48;
-                       break;
-               default:
-                       DBG(1, "Not supported image sensor detected for %s",
-                           symbolic(camlist, cam->id))
-                       return -EINVAL;
-       }
-
-       /* These values depend on the ones in the ovxxx0.c sources */
-       switch (cam->sensor) {
-               case CC_OV7620:
-                       cam->start_cropx = 287;
-                       cam->start_cropy = 35;
-                       /* Seems to work around a bug in the image sensor */
-                       cam->vs_polarity = 1;
-                       cam->hs_polarity = 1;
-                       break;
-               default:
-                       cam->start_cropx = 320;
-                       cam->start_cropy = 35;
-                       cam->vs_polarity = 1;
-                       cam->hs_polarity = 0;
-       }
-
-       if ((err = w9968cf_sensor_update_settings(cam)))
-               goto error;
-
-       if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
-               goto error;
-
-       cam->sensor_initialized = 1;
-
-       DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
-       return 0;
-
-error:
-       cam->sensor_initialized = 0;
-       cam->sensor = CC_UNKNOWN;
-       DBG(1, "Image sensor initialization failed for %s (%s). "
-              "Try to detach and attach this device again",
-           symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Fill some basic fields in the main device data structure.
-  This function is called once on w9968cf_usb_probe() for each recognized
-  camera.
-  --------------------------------------------------------------------------*/
-static void
-w9968cf_configure_camera(struct w9968cf_device* cam,
-                        struct usb_device* udev,
-                        enum w9968cf_model_id mod_id,
-                        const unsigned short dev_nr)
-{
-       mutex_init(&cam->fileop_mutex);
-       init_waitqueue_head(&cam->open);
-       spin_lock_init(&cam->urb_lock);
-       spin_lock_init(&cam->flist_lock);
-
-       cam->users = 0;
-       cam->disconnected = 0;
-       cam->id = mod_id;
-       cam->sensor = CC_UNKNOWN;
-       cam->sensor_initialized = 0;
-
-       /* Calculate the alternate setting number (from 1 to 16)
-          according to the 'packet_size' module parameter */
-       if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
-               packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
-       for (cam->altsetting = 1;
-            packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
-            cam->altsetting++);
-
-       cam->max_buffers = (max_buffers[dev_nr] < 2 ||
-                           max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
-                          ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
-
-       cam->double_buffer = (double_buffer[dev_nr] == 0 ||
-                             double_buffer[dev_nr] == 1)
-                            ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
-
-       cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
-                       ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
-
-       cam->filter_type = (filter_type[dev_nr] == 0 ||
-                           filter_type[dev_nr] == 1 ||
-                           filter_type[dev_nr] == 2)
-                          ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
-
-       cam->capture = 1;
-
-       cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
-                        ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
-
-       cam->decompression = (decompression[dev_nr] == 0 ||
-                             decompression[dev_nr] == 1 ||
-                             decompression[dev_nr] == 2)
-                            ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
-
-       cam->upscaling = (upscaling[dev_nr] == 0 ||
-                         upscaling[dev_nr] == 1)
-                        ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
-
-       cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
-                       ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
-
-       cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
-                       ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
-
-       cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
-                        ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
-
-       cam->bandfilt = (bandingfilter[dev_nr] == 0 ||
-                        bandingfilter[dev_nr] == 1)
-                       ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
-
-       cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
-                        ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
-
-       cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
-                       ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
-
-       cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
-                     ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
-
-       cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
-                         ? monochrome[dev_nr] : W9968CF_MONOCHROME;
-
-       cam->picture.brightness = (u16)brightness[dev_nr];
-       cam->picture.hue = (u16)hue[dev_nr];
-       cam->picture.colour = (u16)colour[dev_nr];
-       cam->picture.contrast = (u16)contrast[dev_nr];
-       cam->picture.whiteness = (u16)whiteness[dev_nr];
-       if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
-               cam->picture.palette = (u16)force_palette[dev_nr];
-               cam->force_palette = 1;
-       } else {
-               cam->force_palette = 0;
-               if (cam->decompression == 0)
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
-               else if (cam->decompression == 1)
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
-               else
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
-       }
-       cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-
-       cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
-                        ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
-
-       cam->window.x = 0;
-       cam->window.y = 0;
-       cam->window.width = W9968CF_WIDTH;
-       cam->window.height = W9968CF_HEIGHT;
-       cam->window.chromakey = 0;
-       cam->window.clipcount = 0;
-       cam->window.flags = 0;
-
-       DBG(3, "%s configured with settings #%u:",
-           symbolic(camlist, cam->id), dev_nr)
-
-       DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
-           wMaxPacketSize[cam->altsetting-1])
-
-       DBG(3, "- Number of requested video frame buffers: %u",
-           cam->max_buffers)
-
-       if (cam->double_buffer)
-               DBG(3, "- Hardware double buffering enabled")
-       else
-               DBG(3, "- Hardware double buffering disabled")
-
-       if (cam->filter_type == 0)
-               DBG(3, "- Video filtering disabled")
-       else if (cam->filter_type == 1)
-               DBG(3, "- Video filtering enabled: type 1-2-1")
-       else if (cam->filter_type == 2)
-               DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
-
-       if (cam->clamping)
-               DBG(3, "- Video data clamping (CCIR-601 format) enabled")
-       else
-               DBG(3, "- Video data clamping (CCIR-601 format) disabled")
-
-       if (cam->largeview)
-               DBG(3, "- Large view enabled")
-       else
-               DBG(3, "- Large view disabled")
-
-       if ((cam->decompression) == 0 && (!cam->force_palette))
-               DBG(3, "- Decompression disabled")
-       else if ((cam->decompression) == 1 && (!cam->force_palette))
-               DBG(3, "- Decompression forced")
-       else if ((cam->decompression) == 2 && (!cam->force_palette))
-               DBG(3, "- Decompression allowed")
-
-       if (cam->upscaling)
-               DBG(3, "- Software image scaling enabled")
-       else
-               DBG(3, "- Software image scaling disabled")
-
-       if (cam->force_palette)
-               DBG(3, "- Image palette forced to %s",
-                   symbolic(v4l1_plist, cam->picture.palette))
-
-       if (cam->force_rgb)
-               DBG(3, "- RGB component ordering will be used instead of BGR")
-
-       if (cam->auto_brt)
-               DBG(3, "- Auto brightness enabled")
-       else
-               DBG(3, "- Auto brightness disabled")
-
-       if (cam->auto_exp)
-               DBG(3, "- Auto exposure enabled")
-       else
-               DBG(3, "- Auto exposure disabled")
-
-       if (cam->backlight)
-               DBG(3, "- Backlight exposure algorithm enabled")
-       else
-               DBG(3, "- Backlight exposure algorithm disabled")
-
-       if (cam->mirror)
-               DBG(3, "- Mirror enabled")
-       else
-               DBG(3, "- Mirror disabled")
-
-       if (cam->bandfilt)
-               DBG(3, "- Banding filter enabled")
-       else
-               DBG(3, "- Banding filter disabled")
-
-       DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
-
-       if (cam->clockdiv == -1)
-               DBG(3, "- Automatic clock divisor enabled")
-       else
-               DBG(3, "- Clock divisor: %d", cam->clockdiv)
-
-       if (cam->monochrome)
-               DBG(3, "- Image sensor used as monochrome")
-       else
-               DBG(3, "- Image sensor not used as monochrome")
-}
-
-
-/*--------------------------------------------------------------------------
-  If the video post-processing module is not loaded, some parameters
-  must be overridden.
-  --------------------------------------------------------------------------*/
-static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
-{
-       if (!w9968cf_vpp) {
-               if (cam->decompression == 1) {
-                       cam->decompression = 2;
-                       DBG(2, "Video post-processing module not found: "
-                              "'decompression' parameter forced to 2")
-               }
-               if (cam->upscaling) {
-                       cam->upscaling = 0;
-                       DBG(2, "Video post-processing module not found: "
-                              "'upscaling' parameter forced to 0")
-               }
-               if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
-                       cam->force_palette = 0;
-                       DBG(2, "Video post-processing module not found: "
-                              "'force_palette' parameter forced to 0")
-               }
-               cam->picture.palette = VIDEO_PALETTE_UYVY;
-               cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-       }
-}
-
-
-/*--------------------------------------------------------------------------
-  Release the resources used by the driver.
-  This function is called on disconnect
-  (or on close if deallocation has been deferred)
-  --------------------------------------------------------------------------*/
-static void w9968cf_release_resources(struct w9968cf_device* cam)
-{
-       mutex_lock(&w9968cf_devlist_mutex);
-
-       DBG(2, "V4L device deregistered: %s",
-           video_device_node_name(cam->v4ldev))
-
-       video_unregister_device(cam->v4ldev);
-       list_del(&cam->v4llist);
-       i2c_del_adapter(&cam->i2c_adapter);
-       w9968cf_deallocate_memory(cam);
-       kfree(cam->control_buffer);
-       kfree(cam->data_buffer);
-       v4l2_device_unregister(&cam->v4l2_dev);
-
-       mutex_unlock(&w9968cf_devlist_mutex);
-}
-
-
-
-/****************************************************************************
- * Video4Linux interface                                                    *
- ****************************************************************************/
-
-static int w9968cf_open(struct file *filp)
-{
-       struct w9968cf_device* cam;
-       int err;
-
-       /* This the only safe way to prevent race conditions with disconnect */
-       if (!down_read_trylock(&w9968cf_disconnect))
-               return -EAGAIN;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex);
-
-       if (cam->sensor == CC_UNKNOWN) {
-               DBG(2, "No supported image sensor has been detected by the "
-                      "'ovcamchip' module for the %s (%s). Make sure "
-                      "it is loaded *before* (re)connecting the camera.",
-                   symbolic(camlist, cam->id),
-                   video_device_node_name(cam->v4ldev))
-               mutex_unlock(&cam->dev_mutex);
-               up_read(&w9968cf_disconnect);
-               return -ENODEV;
-       }
-
-       if (cam->users) {
-               DBG(2, "%s (%s) has been already occupied by '%s'",
-                   symbolic(camlist, cam->id),
-                   video_device_node_name(cam->v4ldev), cam->command)
-               if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
-                       mutex_unlock(&cam->dev_mutex);
-                       up_read(&w9968cf_disconnect);
-                       return -EWOULDBLOCK;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                        cam->disconnected ||
-                                                        !cam->users);
-               if (err) {
-                       up_read(&w9968cf_disconnect);
-                       return err;
-               }
-               if (cam->disconnected) {
-                       up_read(&w9968cf_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-       DBG(5, "Opening '%s', %s ...",
-           symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
-
-       cam->streaming = 0;
-       cam->misconfigured = 0;
-
-       w9968cf_adjust_configuration(cam);
-
-       if ((err = w9968cf_allocate_memory(cam)))
-               goto deallocate_memory;
-
-       if ((err = w9968cf_init_chip(cam)))
-               goto deallocate_memory;
-
-       if ((err = w9968cf_start_transfer(cam)))
-               goto deallocate_memory;
-
-       filp->private_data = cam;
-
-       cam->users++;
-       strcpy(cam->command, current->comm);
-
-       init_waitqueue_head(&cam->wait_queue);
-
-       DBG(5, "Video device is open")
-
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&w9968cf_disconnect);
-
-       return 0;
-
-deallocate_memory:
-       w9968cf_deallocate_memory(cam);
-       DBG(2, "Failed to open the video device")
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&w9968cf_disconnect);
-       return err;
-}
-
-
-static int w9968cf_release(struct file *filp)
-{
-       struct w9968cf_device* cam;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       w9968cf_stop_transfer(cam);
-
-       if (cam->disconnected) {
-               w9968cf_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       w9968cf_deallocate_memory(cam);
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(5, "Video device closed")
-       mutex_unlock(&cam->dev_mutex);
-       return 0;
-}
-
-
-static ssize_t
-w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct w9968cf_device* cam;
-       struct w9968cf_frame_t* fr;
-       int err = 0;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       if (filp->f_flags & O_NONBLOCK)
-               return -EWOULDBLOCK;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again.")
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (!cam->frame[0].queued)
-               w9968cf_push_frame(cam, 0);
-
-       if (!cam->frame[1].queued)
-               w9968cf_push_frame(cam, 1);
-
-       err = wait_event_interruptible(cam->wait_queue,
-                                      cam->frame[0].status == F_READY ||
-                                      cam->frame[1].status == F_READY ||
-                                      cam->disconnected);
-       if (err) {
-               mutex_unlock(&cam->fileop_mutex);
-               return err;
-       }
-       if (cam->disconnected) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
-
-       if (w9968cf_vpp)
-               w9968cf_postprocess_frame(cam, fr);
-
-       if (count > fr->length)
-               count = fr->length;
-
-       if (copy_to_user(buf, fr->buffer, count)) {
-               fr->status = F_UNUSED;
-               mutex_unlock(&cam->fileop_mutex);
-               return -EFAULT;
-       }
-       *f_pos += count;
-
-       fr->status = F_UNUSED;
-
-       DBG(5, "%zu bytes read", count)
-
-       mutex_unlock(&cam->fileop_mutex);
-       return count;
-}
-
-
-static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct w9968cf_device* cam = (struct w9968cf_device*)
-                                    video_get_drvdata(video_devdata(filp));
-       unsigned long vsize = vma->vm_end - vma->vm_start,
-                     psize = cam->nbuffers * cam->frame[0].size,
-                     start = vma->vm_start,
-                     pos = (unsigned long)cam->frame[0].buffer,
-                     page;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again")
-               return -EIO;
-       }
-
-       PDBGG("mmapping %lu bytes...", vsize)
-
-       if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
-               return -EINVAL;
-
-       while (vsize > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
-                                               PAGE_SIZE, vma->vm_page_prot))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               vsize -= PAGE_SIZE;
-       }
-
-       DBG(5, "mmap method successfully called")
-       return 0;
-}
-
-
-static long
-w9968cf_ioctl(struct file *filp,
-             unsigned int cmd, unsigned long arg)
-{
-       struct w9968cf_device* cam;
-       long err;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again.")
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-       return err;
-}
-
-
-static long w9968cf_v4l_ioctl(struct file *filp,
-                            unsigned int cmd, void __user *arg)
-{
-       struct w9968cf_device* cam;
-       const char* v4l1_ioctls[] = {
-               "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
-               "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
-               "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
-               "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
-               "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE",
-               "GVBIFMT", "SVBIFMT"
-       };
-
-       #define V4L1_IOCTL(cmd) \
-               ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
-               v4l1_ioctls[_IOC_NR((cmd))] : "?")
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOCGCAP: /* get video capability */
-       {
-               struct video_capability cap = {
-                       .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
-                       .channels = 1,
-                       .audios = 0,
-                       .minwidth = cam->minwidth,
-                       .minheight = cam->minheight,
-               };
-               sprintf(cap.name, "W996[87]CF USB Camera");
-               cap.maxwidth = (cam->upscaling && w9968cf_vpp)
-                              ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
-                                : cam->maxwidth;
-               cap.maxheight = (cam->upscaling && w9968cf_vpp)
-                               ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-                                 : cam->maxheight;
-
-               if (copy_to_user(arg, &cap, sizeof(cap)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGCAP successfully called")
-               return 0;
-       }
-
-       case VIDIOCGCHAN: /* get video channel informations */
-       {
-               struct video_channel chan;
-               if (copy_from_user(&chan, arg, sizeof(chan)))
-                       return -EFAULT;
-
-               if (chan.channel != 0)
-                       return -EINVAL;
-
-               strcpy(chan.name, "Camera");
-               chan.tuners = 0;
-               chan.flags = 0;
-               chan.type = VIDEO_TYPE_CAMERA;
-               chan.norm = VIDEO_MODE_AUTO;
-
-               if (copy_to_user(arg, &chan, sizeof(chan)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGCHAN successfully called")
-               return 0;
-       }
-
-       case VIDIOCSCHAN: /* set active channel */
-       {
-               struct video_channel chan;
-
-               if (copy_from_user(&chan, arg, sizeof(chan)))
-                       return -EFAULT;
-
-               if (chan.channel != 0)
-                       return -EINVAL;
-
-               DBG(5, "VIDIOCSCHAN successfully called")
-               return 0;
-       }
-
-       case VIDIOCGPICT: /* get image properties of the picture */
-       {
-               if (w9968cf_sensor_get_picture(cam))
-                       return -EIO;
-
-               if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGPICT successfully called")
-               return 0;
-       }
-
-       case VIDIOCSPICT: /* change picture settings */
-       {
-               struct video_picture pict;
-               int err = 0;
-
-               if (copy_from_user(&pict, arg, sizeof(pict)))
-                       return -EFAULT;
-
-               if ( (cam->force_palette || !w9968cf_vpp)
-                    && pict.palette != cam->picture.palette ) {
-                       DBG(4, "Palette %s rejected: only %s is allowed",
-                           symbolic(v4l1_plist, pict.palette),
-                           symbolic(v4l1_plist, cam->picture.palette))
-                       return -EINVAL;
-               }
-
-               if (!w9968cf_valid_palette(pict.palette)) {
-                       DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
-                           symbolic(v4l1_plist, pict.palette))
-                       return -EINVAL;
-               }
-
-               if (!cam->force_palette) {
-                  if (cam->decompression == 0) {
-                     if (w9968cf_need_decompression(pict.palette)) {
-                        DBG(4, "Decompression disabled: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, pict.palette))
-                        return -EINVAL;
-                     }
-                  } else if (cam->decompression == 1) {
-                     if (!w9968cf_need_decompression(pict.palette)) {
-                        DBG(4, "Decompression forced: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, pict.palette))
-                        return -EINVAL;
-                     }
-                  }
-               }
-
-               if (pict.depth != w9968cf_valid_depth(pict.palette)) {
-                       DBG(4, "Requested depth %u bpp is not valid for %s "
-                              "palette: ignored and changed to %u bpp",
-                           pict.depth, symbolic(v4l1_plist, pict.palette),
-                           w9968cf_valid_depth(pict.palette))
-                       pict.depth = w9968cf_valid_depth(pict.palette);
-               }
-
-               if (pict.palette != cam->picture.palette) {
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_picture(cam, pict))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-
-               } else if (w9968cf_sensor_update_picture(cam, pict))
-                       return -EIO;
-
-
-               DBG(5, "VIDIOCSPICT successfully called")
-               return 0;
-       }
-
-       case VIDIOCSWIN: /* set capture area */
-       {
-               struct video_window win;
-               int err = 0;
-
-               if (copy_from_user(&win, arg, sizeof(win)))
-                       return -EFAULT;
-
-               DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
-                      "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
-                   win.x, win.y, win.width, win.height)
-
-               if (win.clipcount != 0 || win.flags != 0)
-                       return -EINVAL;
-
-               if ((err = w9968cf_adjust_window_size(cam, &win.width,
-                                                     &win.height))) {
-                       DBG(4, "Resolution not supported (%ux%u). "
-                              "VIDIOCSWIN failed", win.width, win.height)
-                       return err;
-               }
-
-               if (win.x != cam->window.x ||
-                   win.y != cam->window.y ||
-                   win.width != cam->window.width ||
-                   win.height != cam->window.height) {
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       /* This _must_ be called before set_window() */
-                       if (w9968cf_set_picture(cam, cam->picture))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_window(cam, win))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-               }
-
-               DBG(5, "VIDIOCSWIN successfully called. ")
-               return 0;
-       }
-
-       case VIDIOCGWIN: /* get current window properties */
-       {
-               if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGWIN successfully called")
-               return 0;
-       }
-
-       case VIDIOCGMBUF: /* request for memory (mapped) buffer */
-       {
-               struct video_mbuf mbuf;
-               u8 i;
-
-               mbuf.size = cam->nbuffers * cam->frame[0].size;
-               mbuf.frames = cam->nbuffers;
-               for (i = 0; i < cam->nbuffers; i++)
-                       mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
-                                         (unsigned long)cam->frame[0].buffer;
-
-               if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGMBUF successfully called")
-               return 0;
-       }
-
-       case VIDIOCMCAPTURE: /* start the capture to a frame */
-       {
-               struct video_mmap mmap;
-               struct w9968cf_frame_t* fr;
-               u32 w, h;
-               int err = 0;
-
-               if (copy_from_user(&mmap, arg, sizeof(mmap)))
-                       return -EFAULT;
-
-               DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
-                   mmap.frame, symbolic(v4l1_plist, mmap.format),
-                   mmap.width, mmap.height)
-
-               if (mmap.frame >= cam->nbuffers) {
-                       DBG(4, "Invalid frame number (%u). "
-                              "VIDIOCMCAPTURE failed", mmap.frame)
-                       return -EINVAL;
-               }
-
-               if (mmap.format!=cam->picture.palette &&
-                   (cam->force_palette || !w9968cf_vpp)) {
-                       DBG(4, "Palette %s rejected: only %s is allowed",
-                           symbolic(v4l1_plist, mmap.format),
-                           symbolic(v4l1_plist, cam->picture.palette))
-                       return -EINVAL;
-               }
-
-               if (!w9968cf_valid_palette(mmap.format)) {
-                       DBG(4, "Palette %s not supported. "
-                              "VIDIOCMCAPTURE failed",
-                           symbolic(v4l1_plist, mmap.format))
-                       return -EINVAL;
-               }
-
-               if (!cam->force_palette) {
-                  if (cam->decompression == 0) {
-                     if (w9968cf_need_decompression(mmap.format)) {
-                        DBG(4, "Decompression disabled: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, mmap.format))
-                        return -EINVAL;
-                     }
-                  } else if (cam->decompression == 1) {
-                     if (!w9968cf_need_decompression(mmap.format)) {
-                        DBG(4, "Decompression forced: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, mmap.format))
-                        return -EINVAL;
-                     }
-                  }
-               }
-
-               w = mmap.width; h = mmap.height;
-               err = w9968cf_adjust_window_size(cam, &w, &h);
-               mmap.width = w; mmap.height = h;
-               if (err) {
-                       DBG(4, "Resolution not supported (%dx%d). "
-                              "VIDIOCMCAPTURE failed",
-                           mmap.width, mmap.height)
-                       return err;
-               }
-
-               fr = &cam->frame[mmap.frame];
-
-               if (mmap.width  != cam->window.width ||
-                   mmap.height != cam->window.height ||
-                   mmap.format != cam->picture.palette) {
-
-                       struct video_window win;
-                       struct video_picture pict;
-
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               DBG(6, "VIDIOCMCAPTURE. Change settings for "
-                                      "frame #%u: %dx%d, format %s. Wait...",
-                                   mmap.frame, mmap.width, mmap.height,
-                                   symbolic(v4l1_plist, mmap.format))
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       memcpy(&win, &cam->window, sizeof(win));
-                       memcpy(&pict, &cam->picture, sizeof(pict));
-                       win.width = mmap.width;
-                       win.height = mmap.height;
-                       pict.palette = mmap.format;
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       /* This before set_window */
-                       if (w9968cf_set_picture(cam, pict))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_window(cam, win))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-
-               } else  if (fr->queued) {
-
-                       DBG(6, "Wait until frame #%u is free", mmap.frame)
-
-                       err = wait_event_interruptible(cam->wait_queue,
-                                                      cam->disconnected ||
-                                                      (!fr->queued));
-                       if (err)
-                               return err;
-                       if (cam->disconnected)
-                               return -ENODEV;
-               }
-
-               w9968cf_push_frame(cam, mmap.frame);
-               DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
-               return 0;
-       }
-
-       case VIDIOCSYNC: /* wait until the capture of a frame is finished */
-       {
-               unsigned int f_num;
-               struct w9968cf_frame_t* fr;
-               int err = 0;
-
-               if (copy_from_user(&f_num, arg, sizeof(f_num)))
-                       return -EFAULT;
-
-               if (f_num >= cam->nbuffers) {
-                       DBG(4, "Invalid frame number (%u). "
-                              "VIDIOCMCAPTURE failed", f_num)
-                       return -EINVAL;
-               }
-
-               DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
-
-               fr = &cam->frame[f_num];
-
-               switch (fr->status) {
-               case F_UNUSED:
-                       if (!fr->queued) {
-                               DBG(4, "VIDIOSYNC: Frame #%u not requested!",
-                                   f_num)
-                               return -EFAULT;
-                       }
-               case F_ERROR:
-               case F_GRABBING:
-                       err = wait_event_interruptible(cam->wait_queue,
-                                                      (fr->status == F_READY)
-                                                      || cam->disconnected);
-                       if (err)
-                               return err;
-                       if (cam->disconnected)
-                               return -ENODEV;
-                       break;
-               case F_READY:
-                       break;
-               }
-
-               if (w9968cf_vpp)
-                       w9968cf_postprocess_frame(cam, fr);
-
-               fr->status = F_UNUSED;
-
-               DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
-               return 0;
-       }
-
-       case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
-       {
-               struct video_unit unit = {
-                       .video = cam->v4ldev->minor,
-                       .vbi = VIDEO_NO_UNIT,
-                       .radio = VIDEO_NO_UNIT,
-                       .audio = VIDEO_NO_UNIT,
-                       .teletext = VIDEO_NO_UNIT,
-               };
-
-               if (copy_to_user(arg, &unit, sizeof(unit)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGUNIT successfully called")
-               return 0;
-       }
-
-       case VIDIOCKEY:
-               return 0;
-
-       case VIDIOCGFBUF:
-       {
-               if (clear_user(arg, sizeof(struct video_buffer)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGFBUF successfully called")
-               return 0;
-       }
-
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner tuner;
-               if (copy_from_user(&tuner, arg, sizeof(tuner)))
-                       return -EFAULT;
-
-               if (tuner.tuner != 0)
-                       return -EINVAL;
-
-               strcpy(tuner.name, "no_tuner");
-               tuner.rangelow = 0;
-               tuner.rangehigh = 0;
-               tuner.flags = VIDEO_TUNER_NORM;
-               tuner.mode = VIDEO_MODE_AUTO;
-               tuner.signal = 0xffff;
-
-               if (copy_to_user(arg, &tuner, sizeof(tuner)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGTUNER successfully called")
-               return 0;
-       }
-
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner tuner;
-               if (copy_from_user(&tuner, arg, sizeof(tuner)))
-                       return -EFAULT;
-
-               if (tuner.tuner != 0)
-                       return -EINVAL;
-
-               if (tuner.mode != VIDEO_MODE_AUTO)
-                       return -EINVAL;
-
-               DBG(5, "VIDIOCSTUNER successfully called")
-               return 0;
-       }
-
-       case VIDIOCSFBUF:
-       case VIDIOCCAPTURE:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-       case VIDIOCSPLAYMODE:
-       case VIDIOCSWRITEMODE:
-       case VIDIOCGPLAYINFO:
-       case VIDIOCSMICROCODE:
-       case VIDIOCGVBIFMT:
-       case VIDIOCSVBIFMT:
-               DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
-                      "(type 0x%01X, "
-                      "n. 0x%01X, "
-                      "dir. 0x%01X, "
-                      "size 0x%02X)",
-                   V4L1_IOCTL(cmd),
-                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-               return -EINVAL;
-
-       default:
-               DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
-                      "type 0x%01X, "
-                      "n. 0x%01X, "
-                      "dir. 0x%01X, "
-                      "size 0x%02X",
-                   V4L1_IOCTL(cmd),
-                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-               return -ENOIOCTLCMD;
-
-       } /* end of switch */
-
-ioctl_fail:
-       cam->misconfigured = 1;
-       DBG(1, "VIDIOC%s failed because of hardware problems. "
-              "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
-       return -EFAULT;
-}
-
-
-static const struct v4l2_file_operations w9968cf_fops = {
-       .owner =   THIS_MODULE,
-       .open =    w9968cf_open,
-       .release = w9968cf_release,
-       .read =    w9968cf_read,
-       .ioctl =   w9968cf_ioctl,
-       .mmap =    w9968cf_mmap,
-};
-
-
-
-/****************************************************************************
- * USB probe and V4L registration, disconnect and id_table[] definition     *
- ****************************************************************************/
-
-static int
-w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct w9968cf_device* cam;
-       int err = 0;
-       enum w9968cf_model_id mod_id;
-       struct list_head* ptr;
-       u8 sc = 0; /* number of simultaneous cameras */
-       static unsigned short dev_nr; /* 0 - we are handling device number n */
-       static unsigned short addrs[] = {
-               OV7xx0_SID,
-               OV6xx0_SID,
-               I2C_CLIENT_END
-       };
-
-       if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
-           le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
-               mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
-       else if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[1].idVendor &&
-                le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
-               mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
-       else
-               return -ENODEV;
-
-       cam = (struct w9968cf_device*)
-                 kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
-       if (!cam)
-               return -ENOMEM;
-
-       err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
-       if (err)
-               goto fail0;
-
-       mutex_init(&cam->dev_mutex);
-       mutex_lock(&cam->dev_mutex);
-
-       cam->usbdev = udev;
-
-       DBG(2, "%s detected", symbolic(camlist, mod_id))
-
-       if (simcams > W9968CF_MAX_DEVICES)
-               simcams = W9968CF_SIMCAMS;
-
-       /* How many cameras are connected ? */
-       mutex_lock(&w9968cf_devlist_mutex);
-       list_for_each(ptr, &w9968cf_dev_list)
-               sc++;
-       mutex_unlock(&w9968cf_devlist_mutex);
-
-       if (sc >= simcams) {
-               DBG(2, "Device rejected: too many connected cameras "
-                      "(max. %u)", simcams)
-               err = -EPERM;
-               goto fail;
-       }
-
-
-       /* Allocate 2 bytes of memory for camera control USB transfers */
-       if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
-               DBG(1,"Couldn't allocate memory for camera control transfers")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Allocate 8 bytes of memory for USB data transfers to the FSB */
-       if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "Couldn't allocate memory for data "
-                      "transfers to the FSB")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Register the V4L device */
-       cam->v4ldev = video_device_alloc();
-       if (!cam->v4ldev) {
-               DBG(1, "Could not allocate memory for a V4L structure")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
-       cam->v4ldev->fops = &w9968cf_fops;
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-       cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L device registration failed")
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(2, "Couldn't find a free /dev/videoX node")
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               goto fail;
-       }
-
-       DBG(2, "V4L device registered as %s",
-           video_device_node_name(cam->v4ldev))
-
-       /* Set some basic constants */
-       w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
-
-       /* Add a new entry into the list of V4L registered devices */
-       mutex_lock(&w9968cf_devlist_mutex);
-       list_add(&cam->v4llist, &w9968cf_dev_list);
-       mutex_unlock(&w9968cf_devlist_mutex);
-       dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-       w9968cf_turn_on_led(cam);
-
-       w9968cf_i2c_init(cam);
-       cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
-                       &cam->i2c_adapter,
-                       "ovcamchip", "ovcamchip", 0, addrs);
-
-       usb_set_intfdata(intf, cam);
-       mutex_unlock(&cam->dev_mutex);
-
-       err = w9968cf_sensor_init(cam);
-       return 0;
-
-fail: /* Free unused memory */
-       kfree(cam->control_buffer);
-       kfree(cam->data_buffer);
-       if (cam->v4ldev)
-               video_device_release(cam->v4ldev);
-       mutex_unlock(&cam->dev_mutex);
-       v4l2_device_unregister(&cam->v4l2_dev);
-fail0:
-       kfree(cam);
-       return err;
-}
-
-
-static void w9968cf_usb_disconnect(struct usb_interface* intf)
-{
-       struct w9968cf_device* cam =
-          (struct w9968cf_device*)usb_get_intfdata(intf);
-
-       if (cam) {
-               down_write(&w9968cf_disconnect);
-               /* Prevent concurrent accesses to data */
-               mutex_lock(&cam->dev_mutex);
-
-               cam->disconnected = 1;
-
-               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
-
-               v4l2_device_disconnect(&cam->v4l2_dev);
-
-               wake_up_interruptible_all(&cam->open);
-
-               if (cam->users) {
-                       DBG(2, "The device is open (%s)! "
-                              "Process name: %s. Deregistration and memory "
-                              "deallocation are deferred on close.",
-                           video_device_node_name(cam->v4ldev), cam->command)
-                       cam->misconfigured = 1;
-                       w9968cf_stop_transfer(cam);
-                       wake_up_interruptible(&cam->wait_queue);
-               } else
-                       w9968cf_release_resources(cam);
-
-               mutex_unlock(&cam->dev_mutex);
-               up_write(&w9968cf_disconnect);
-
-               if (!cam->users) {
-                       kfree(cam);
-               }
-       }
-}
-
-
-static struct usb_driver w9968cf_usb_driver = {
-       .name =       "w9968cf",
-       .id_table =   winbond_id_table,
-       .probe =      w9968cf_usb_probe,
-       .disconnect = w9968cf_usb_disconnect,
-};
-
-
-
-/****************************************************************************
- * Module init, exit and intermodule communication                          *
- ****************************************************************************/
-
-static int __init w9968cf_module_init(void)
-{
-       int err;
-
-       KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
-       KDBG(3, W9968CF_MODULE_AUTHOR)
-
-       if ((err = usb_register(&w9968cf_usb_driver)))
-               return err;
-
-       return 0;
-}
-
-
-static void __exit w9968cf_module_exit(void)
-{
-       /* w9968cf_usb_disconnect() will be called */
-       usb_deregister(&w9968cf_usb_driver);
-
-       KDBG(2, W9968CF_MODULE_NAME" deregistered")
-}
-
-
-module_init(w9968cf_module_init);
-module_exit(w9968cf_module_exit);
-
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
deleted file mode 100644 (file)
index 73ad864..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; 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 _W9968CF_H_
-#define _W9968CF_H_
-
-#include <linux/videodev2.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/param.h>
-#include <linux/types.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-
-#include <media/v4l2-device.h>
-#include <media/ovcamchip.h>
-
-#include "w9968cf_vpp.h"
-
-
-/****************************************************************************
- * Default values                                                           *
- ****************************************************************************/
-
-#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
-
-/* Comment/uncomment the following line to enable/disable debugging messages */
-#define W9968CF_DEBUG
-
-/* These have effect only if W9968CF_DEBUG is defined */
-#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
-#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
-
-#define W9968CF_MAX_DEVICES    32
-#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
-
-#define W9968CF_MAX_BUFFERS   32
-#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
-
-/* Maximum data payload sizes in bytes for alternate settings */
-static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
-                                     511, 447, 383, 319, 255, 191, 127,  63};
-#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
-#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
-#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
-#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
-
-#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
-#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
-
-/* Available video formats */
-struct w9968cf_format {
-       const u16 palette;
-       const u16 depth;
-       const u8 compression;
-};
-
-static const struct w9968cf_format w9968cf_formatlist[] = {
-       { VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
-       { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
-       { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
-       { VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
-       { VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
-       { 0,                      0, 0 }  /* 0 is a terminating entry */
-};
-
-#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
-#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
-#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
-#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
-
-#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
-
-#define W9968CF_MAX_WIDTH      800 /* Has effect if up-scaling is on */
-#define W9968CF_MAX_HEIGHT     600 /* Has effect if up-scaling is on */
-#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
-#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
-
-#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
-#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
-#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
-#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
-#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
-
-#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
-#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
-#define W9968CF_HUE            32768 /* from 0 to 65535 */
-#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
-#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
-#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
-
-#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
-#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
-#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
-#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
-#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
-#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
-
-#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
-#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
-
-
-/****************************************************************************
- * Globals                                                                  *
- ****************************************************************************/
-
-#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
-                               "Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION  "1:1.34-basic"
-#define W9968CF_MODULE_AUTHOR   "(C) 2002-2004 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define W9968CF_MODULE_LICENSE  "GPL"
-
-static const struct usb_device_id winbond_id_table[] = {
-       {
-               /* Creative Labs Video Blaster WebCam Go Plus */
-               USB_DEVICE(0x041e, 0x4003),
-               .driver_info = (unsigned long)"w9968cf",
-       },
-       {
-               /* Generic W996[87]CF JPEG USB Dual Mode Camera */
-               USB_DEVICE(0x1046, 0x9967),
-               .driver_info = (unsigned long)"w9968cf",
-       },
-       { } /* terminating entry */
-};
-
-/* W996[87]CF camera models, internal ids: */
-enum w9968cf_model_id {
-       W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
-       W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
-       W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
-       W9986CF_MOD_AAU = 31,     /* AVerMedia AVerTV USB */
-       W9968CF_MOD_CLVBWG = 34,  /* Creative Labs Video Blaster WebCam Go */
-       W9968CF_MOD_LL = 37,      /* Lebon LDC-035A */
-       W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
-       W9968CF_MOD_OOE = 42,     /* OmniVision OV8610-EDE */
-       W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
-       W9968CF_MOD_PDPII = 46,   /* Pretec Digi Pen-II */
-       W9968CF_MOD_PDP480 = 49,  /* Pretec DigiPen-480 */
-};
-
-enum w9968cf_frame_status {
-       F_READY,            /* finished grabbing & ready to be read/synced */
-       F_GRABBING,         /* in the process of being grabbed into */
-       F_ERROR,            /* something bad happened while processing */
-       F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
-};
-
-struct w9968cf_frame_t {
-       void* buffer;
-       unsigned long size;
-       u32 length;
-       int number;
-       enum w9968cf_frame_status status;
-       struct w9968cf_frame_t* next;
-       u8 queued;
-};
-
-enum w9968cf_vpp_flag {
-       VPP_NONE = 0x00,
-       VPP_UPSCALE = 0x01,
-       VPP_SWAP_YUV_BYTES = 0x02,
-       VPP_DECOMPRESSION = 0x04,
-       VPP_UYVY_TO_RGBX = 0x08,
-};
-
-/* Main device driver structure */
-struct w9968cf_device {
-       enum w9968cf_model_id id;   /* private device identifier */
-
-       struct v4l2_device v4l2_dev;
-       struct video_device* v4ldev; /* -> V4L structure */
-       struct list_head v4llist;    /* entry of the list of V4L cameras */
-
-       struct usb_device* usbdev;           /* -> main USB structure */
-       struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
-       void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
-       u16* control_buffer;                 /* -> buffer for control req.*/
-       u16* data_buffer;                    /* -> data to send to the FSB */
-
-       struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
-       struct w9968cf_frame_t frame_tmp; /* temporary frame */
-       struct w9968cf_frame_t frame_vpp; /* helper frame.*/
-       struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
-       struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-
-       u8 max_buffers,   /* number of requested buffers */
-          force_palette, /* yes=1/no=0 */
-          force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
-          double_buffer, /* hardware double buffering yes=1/no=0 */
-          clamping,      /* video data clamping yes=1/no=0 */
-          filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
-          capture,       /* 0=disabled, 1=enabled */
-          largeview,     /* 0=disabled, 1=enabled */
-          decompression, /* 0=disabled, 1=forced, 2=allowed */
-          upscaling;     /* software image scaling, 0=enabled, 1=disabled */
-
-       struct video_picture picture; /* current picture settings */
-       struct video_window window;   /* current window settings */
-
-       u16 hw_depth,    /* depth (used by the chip) */
-           hw_palette,  /* palette (used by the chip) */
-           hw_width,    /* width (used by the chip) */
-           hw_height,   /* height (used by the chip) */
-           hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-           vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-           start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
-           start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
-
-       enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
-
-       u8 nbuffers,      /* number of allocated frame buffers */
-          altsetting,    /* camera alternate setting */
-          disconnected,  /* flag: yes=1, no=0 */
-          misconfigured, /* flag: yes=1, no=0 */
-          users,         /* flag: number of users holding the device */
-          streaming;     /* flag: yes=1, no=0 */
-
-       u8 sensor_initialized; /* flag: yes=1, no=0 */
-
-       /* Determined by the image sensor type: */
-       int sensor,       /* type of image sensor chip (CC_*) */
-           monochrome;   /* image sensor is (probably) monochrome */
-       u16 maxwidth,     /* maximum width supported by the image sensor */
-           maxheight,    /* maximum height supported by the image sensor */
-           minwidth,     /* minimum width supported by the image sensor */
-           minheight;    /* minimum height supported by the image sensor */
-       u8  auto_brt,     /* auto brightness enabled flag */
-           auto_exp,     /* auto exposure enabled flag */
-           backlight,    /* backlight exposure algorithm flag */
-           mirror,       /* image is reversed horizontally */
-           lightfreq,    /* power (lighting) frequency */
-           bandfilt;     /* banding filter enabled flag */
-       s8  clockdiv;     /* clock divisor */
-
-       /* I2C interface to kernel */
-       struct i2c_adapter i2c_adapter;
-       struct v4l2_subdev *sensor_sd;
-
-       /* Locks */
-       struct mutex dev_mutex,    /* for probe, disconnect,open and close */
-                        fileop_mutex; /* for read and ioctl */
-       spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
-                  flist_lock; /* for requested frame list accesses */
-       wait_queue_head_t open, wait_queue;
-
-       char command[16]; /* name of the program holding the device */
-};
-
-static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
-{
-       return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
-}
-
-
-/****************************************************************************
- * Macros for debugging                                                     *
- ****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef W9968CF_DEBUG
-/* For device specific debugging messages */
-#      define DBG(level, fmt, args...)                                       \
-{                                                                             \
-       if ( ((specific_debug) && (debug == (level))) ||                      \
-            ((!specific_debug) && (debug >= (level))) ) {                    \
-               if ((level) == 1)                                             \
-                       v4l2_err(&cam->v4l2_dev, fmt "\n", ## args);          \
-               else if ((level) == 2 || (level) == 3)                        \
-                       v4l2_info(&cam->v4l2_dev, fmt "\n", ## args);         \
-               else if ((level) == 4)                                        \
-                       v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args);         \
-               else if ((level) >= 5)                                        \
-                       v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n",        \
-                                __func__, __LINE__ , ## args);               \
-       }                                                                     \
-}
-/* For generic kernel (not device specific) messages */
-#      define KDBG(level, fmt, args...)                                      \
-{                                                                             \
-       if ( ((specific_debug) && (debug == (level))) ||                      \
-            ((!specific_debug) && (debug >= (level))) ) {                    \
-               if ((level) >= 1 && (level) <= 4)                             \
-                       pr_info("w9968cf: " fmt "\n", ## args);               \
-               else if ((level) >= 5)                                        \
-                       pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__,  \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-}
-#else
-       /* Not debugging: nothing */
-#      define DBG(level, fmt, args...) do {;} while(0);
-#      define KDBG(level, fmt, args...) do {;} while(0);
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
-
-#endif /* _W9968CF_H_ */
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h
deleted file mode 100644 (file)
index 59decbf..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Video decoder for the W996[87]CF driver for Linux.                      *
- *                                                                         *
- * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; 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 _W9968CF_DECODER_H_
-#define _W9968CF_DECODER_H_
-
-/* Comment/uncomment this for high/low quality of compressed video */
-#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-
-#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-static const unsigned char Y_QUANTABLE[64] = {
-       16,  11,  10,  16,  24,  40,  51,  61,
-       12,  12,  14,  19,  26,  58,  60,  55,
-       14,  13,  16,  24,  40,  57,  69,  56,
-       14,  17,  22,  29,  51,  87,  80,  62,
-       18,  22,  37,  56,  68, 109, 103,  77,
-       24,  35,  55,  64,  81, 104, 113,  92,
-       49,  64,  78,  87, 103, 121, 120, 101,
-       72,  92,  95,  98, 112, 100, 103,  99
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-       17,  18,  24,  47,  99,  99,  99,  99,
-       18,  21,  26,  66,  99,  99,  99,  99,
-       24,  26,  56,  99,  99,  99,  99,  99,
-       47,  66,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99
-};
-#else
-static const unsigned char Y_QUANTABLE[64] = {
-        8,   5,   5,   8,  12,  20,  25,  30,
-        6,   6,   7,   9,  13,  29,  30,  27,
-        7,   6,   8,  12,  20,  28,  34,  28,
-        7,   8,  11,  14,  25,  43,  40,  31,
-        9,  11,  18,  28,  34,  54,  51,  38,
-       12,  17,  27,  32,  40,  52,  56,  46,
-       24,  32,  39,  43,  51,  60,  60,  50,
-       36,  46,  47,  49,  56,  50,  51,  49
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-        8,   9,  12,  23,  49,  49,  49,  49,
-        9,  10,  13,  33,  49,  49,  49,  49,
-       12,  13,  28,  49,  49,  49,  49,  49,
-       23,  33,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49
-};
-#endif
-
-#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
-#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
-#define W9968CF_DEC_ERR_NO_SOI          -3
-#define W9968CF_DEC_ERR_NO_SOF0         -4
-#define W9968CF_DEC_ERR_NO_SOS          -5
-#define W9968CF_DEC_ERR_NO_EOI          -6
-
-extern void w9968cf_init_decoder(void);
-extern int w9968cf_check_headers(const unsigned char* Pin,
-                                const unsigned long BUF_SIZE);
-extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE,
-                         const unsigned W, const unsigned H, char* Pout);
-
-#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h
deleted file mode 100644 (file)
index 88c9b6c..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- * Interface for video post-processing functions for the W996[87]CF driver *
- * for Linux.                                                              *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; 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 _W9968CF_VPP_H_
-#define _W9968CF_VPP_H_
-
-#include <linux/module.h>
-#include <asm/types.h>
-
-struct w9968cf_vpp_t {
-       struct module* owner;
-       int (*check_headers)(const unsigned char*, const unsigned long);
-       int (*decode)(const char*, const unsigned long, const unsigned,
-                     const unsigned, char*);
-       void (*swap_yuvbytes)(void*, unsigned long);
-       void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
-       void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
-
-       u8 busy; /* read-only flag: module is/is not in use */
-};
-
-#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
deleted file mode 100644 (file)
index a7e610e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_ZC0301
-       tristate "USB ZC0301[P] webcam support (DEPRECATED)"
-       depends on VIDEO_V4L2
-       default n
-       ---help---
-         This driver is DEPRECATED please use the gspca zc3xx module
-         instead.
-
-         Say Y here if you want support for cameras based on the ZC0301 or
-         ZC0301P Image Processors and Control Chips.
-
-         See <file:Documentation/video4linux/zc0301.txt> for more info.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zc0301.
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
deleted file mode 100644 (file)
index d9e6d97..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-zc0301-objs     := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
-
-obj-$(CONFIG_USB_ZC0301)        += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
deleted file mode 100644 (file)
index b1b5cce..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ZC0301[P] Image Processor and Control Chip              *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; 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 _ZC0301_H_
-#define _ZC0301_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kref.h>
-
-#include "zc0301_sensor.h"
-
-/*****************************************************************************/
-
-#define ZC0301_DEBUG
-#define ZC0301_DEBUG_LEVEL         2
-#define ZC0301_MAX_DEVICES         64
-#define ZC0301_FORCE_MUNMAP        0
-#define ZC0301_MAX_FRAMES          32
-#define ZC0301_COMPRESSION_QUALITY 0
-#define ZC0301_URBS                2
-#define ZC0301_ISO_PACKETS         7
-#define ZC0301_ALTERNATE_SETTING   7
-#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
-#define ZC0301_CTRL_TIMEOUT        100
-#define ZC0301_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-ZC0301_ID_TABLE
-ZC0301_SENSOR_TABLE
-
-enum zc0301_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct zc0301_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum zc0301_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum zc0301_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum zc0301_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum zc0301_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-struct zc0301_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DECLARE_RWSEM(zc0301_dev_lock);
-
-struct zc0301_device {
-       struct video_device* v4ldev;
-
-       struct zc0301_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[ZC0301_URBS];
-       void* transfer_buffer[ZC0301_URBS];
-       u8* control_buffer;
-
-       struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum zc0301_io_method io;
-       enum zc0301_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct zc0301_module_param module_param;
-
-       struct kref kref;
-       enum zc0301_dev_state state;
-       u8 users;
-
-       struct completion probe;
-       struct mutex open_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
-{
-       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ZC0301_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
-                                __FILE__, __func__, __LINE__ , ## args); \
-       }                                                                     \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("zc0301: " fmt "\n", ## args);                \
-               else if ((level) == 3)                                        \
-                       pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
-                                __func__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__,   \
-        __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ZC0301_H_ */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
deleted file mode 100644 (file)
index bb51cfb..0000000
+++ /dev/null
@@ -1,2098 +0,0 @@
-/***************************************************************************
- * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip      *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * Informations about the chip internals needed to enable the I2C protocol *
- * have been taken from the documentation of the ZC030x Video4Linux1       *
- * driver written by Andrew Birkett <andy@nobugs.org>                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "zc0301.h"
-
-/*****************************************************************************/
-
-#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
-                             "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
-#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.10"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 10)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, zc0301_id_table);
-
-MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
-MODULE_VERSION(ZC0301_MODULE_VERSION);
-MODULE_LICENSE(ZC0301_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                "\n -1 = use next available (default)"
-                "\n  n = use minor number n (integer >= 0)"
-                "\nYou can specify up to "
-                __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
-                "\nFor example:"
-                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                "\nthe second registered camera and use auto for the first"
-                "\none and for every other camera."
-                "\n");
-
-static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-                              ZC0301_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                "\n<0|1[,...]> Force the application to unmap previously"
-                "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                "\nthis feature. This parameter is specific for each"
-                "\ndetected camera."
-                "\n 0 = do not force memory unmapping"
-                "\n 1 = force memory unmapping (save memory)"
-                "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
-                "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-                                      ZC0301_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                "\n<n[,...]> Timeout for a video frame in seconds."
-                "\nThis parameter is specific for each detected camera."
-                "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
-                "\n");
-
-#ifdef ZC0301_DEBUG
-static unsigned short debug = ZC0301_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                "\n<n> Debugging information level, from 0 to 3:"
-                "\n0 = none (use carefully)"
-                "\n1 = critical errors"
-                "\n2 = significant informations"
-                "\n3 = more verbose messages"
-                "\nLevel 3 is useful for testing only, when only "
-                "one device is used."
-                "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
-                "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-zc0301_request_buffers(struct zc0301_device* cam, u32 count,
-                      enum zc0301_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > ZC0301_MAX_FRAMES)
-               count = ZC0301_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32_user(cam->nbuffers *
-                                           PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void zc0301_release_buffers(struct zc0301_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void zc0301_empty_framequeues(struct zc0301_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void zc0301_requeue_outqueue(struct zc0301_device* cam)
-{
-       struct zc0301_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void zc0301_queue_unusedframes(struct zc0301_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
-{
-       struct usb_device* udev = cam->usbdev;
-       int res;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
-                             value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (index 0x%04X, "
-                      "value 0x%02X, error %d)",index, value, res);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-int zc0301_read_reg(struct zc0301_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
-                             0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%04X, error %d)",
-                   index, res);
-
-       PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
-{
-       int err = 0, res, r0, r1;
-
-       err += zc0301_write_reg(cam, 0x0092, address);
-       err += zc0301_write_reg(cam, 0x0090, 0x02);
-
-       msleep(1);
-
-       res = zc0301_read_reg(cam, 0x0091);
-       if (res < 0)
-               err += res;
-       r0 = zc0301_read_reg(cam, 0x0095);
-       if (r0 < 0)
-               err += r0;
-       r1 = zc0301_read_reg(cam, 0x0096);
-       if (r1 < 0)
-               err += r1;
-
-       res = (length <= 1) ? r0 : r0 | (r1 << 8);
-
-       if (err)
-               DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
-                   address, res);
-
-
-       PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
-
-       return err ? -1 : res;
-}
-
-
-int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
-{
-       int err = 0, res;
-
-       err += zc0301_write_reg(cam, 0x0092, address);
-       err += zc0301_write_reg(cam, 0x0093, value & 0xff);
-       err += zc0301_write_reg(cam, 0x0094, value >> 8);
-       err += zc0301_write_reg(cam, 0x0090, 0x01);
-
-       msleep(1);
-
-       res = zc0301_read_reg(cam, 0x0091);
-       if (res < 0)
-               err += res;
-
-       if (err)
-               DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
-                   address, value);
-
-       PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
-
-       return err ? -1 : 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_urb_complete(struct urb *urb)
-{
-       struct zc0301_device* cam = urb->context;
-       struct zc0301_frame_t** f;
-       size_t imagesize;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int len, status;
-               void *pos;
-               u16* soi;
-               u8 sof;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               sof = (*(soi = pos) == 0xd8ff);
-
-               PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
-
-               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-                       if (sof) {
-                               (*f)->state = F_GRABBING;
-                               (*f)->buf.bytesused = 0;
-                               do_gettimeofday(&(*f)->buf.timestamp);
-                               DBG(3, "SOF detected: new video frame");
-                       }
-
-               if ((*f)->state == F_GRABBING) {
-                       if (sof && (*f)->buf.bytesused)
-                                       goto end_of_frame;
-
-                       if ((*f)->buf.bytesused + len > imagesize) {
-                               DBG(3, "Video frame size exceeded");
-                               (*f)->state = F_ERROR;
-                               continue;
-                       }
-
-                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
-                       (*f)->buf.bytesused += len;
-
-                       if ((*f)->buf.bytesused == imagesize) {
-                               u32 b;
-end_of_frame:
-                               b = (*f)->buf.bytesused;
-                               (*f)->state = F_DONE;
-                               (*f)->buf.sequence= ++cam->frame_count;
-                               spin_lock(&cam->queue_lock);
-                               list_move_tail(&(*f)->frame, &cam->outqueue);
-                               if (!list_empty(&cam->inqueue))
-                                       (*f) = list_entry(cam->inqueue.next,
-                                                      struct zc0301_frame_t,
-                                                         frame);
-                               else
-                                       (*f) = NULL;
-                               spin_unlock(&cam->queue_lock);
-                               DBG(3, "Video frame captured: : %lu bytes",
-                                      (unsigned long)(b));
-
-                               if (!(*f))
-                                       goto resubmit_urb;
-
-                               if (sof)
-                                       goto start_of_frame;
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int zc0301_start_transfer(struct zc0301_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
-                                                    usb_ifnum_to_if(udev, 0),
-                                                    ZC0301_ALTERNATE_SETTING);
-       const unsigned int psz = le16_to_cpu(altsetting->
-                                            endpoint[0].desc.wMaxPacketSize);
-       struct urb* urb;
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = ZC0301_ISO_PACKETS;
-               urb->complete = zc0301_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int zc0301_stop_transfer(struct zc0301_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = ZC0301_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int zc0301_stream_interrupt(struct zc0301_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    ZC0301_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. To "
-                      "use it, close and open %s again.",
-                   video_device_node_name(cam->v4ldev));
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_set_compression(struct zc0301_device* cam,
-                      struct v4l2_jpegcompression* compression)
-{
-       int r, err = 0;
-
-       if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
-               err += r;
-       err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
-
-       return err ? -EIO : 0;
-}
-
-
-static int zc0301_init(struct zc0301_device* cam)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->open_mutex);
-               init_waitqueue_head(&cam->wait_open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-               cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       if ((err = zc0301_set_compression(cam, &cam->compression))) {
-               DBG(3, "set_compression() failed");
-               return err;
-       }
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_release_resources(struct kref *kref)
-{
-       struct zc0301_device *cam = container_of(kref, struct zc0301_device,
-                                                kref);
-       DBG(2, "V4L2 device %s deregistered",
-           video_device_node_name(cam->v4ldev));
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-       usb_put_dev(cam->usbdev);
-       kfree(cam->control_buffer);
-       kfree(cam);
-}
-
-
-static int zc0301_open(struct file *filp)
-{
-       struct zc0301_device* cam;
-       int err = 0;
-
-       if (!down_read_trylock(&zc0301_dev_lock))
-               return -EAGAIN;
-
-       cam = video_drvdata(filp);
-
-       if (wait_for_completion_interruptible(&cam->probe)) {
-               up_read(&zc0301_dev_lock);
-               return -ERESTARTSYS;
-       }
-
-       kref_get(&cam->kref);
-
-       if (mutex_lock_interruptible(&cam->open_mutex)) {
-               kref_put(&cam->kref, zc0301_release_resources);
-               up_read(&zc0301_dev_lock);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               err = -ENODEV;
-               goto out;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device %s is busy...",
-                   video_device_node_name(cam->v4ldev));
-               DBG(3, "Simultaneous opens are not supported");
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               DBG(2, "A blocking open() has been requested. Wait for the "
-                      "device to be released...");
-               up_read(&zc0301_dev_lock);
-               err = wait_event_interruptible_exclusive(cam->wait_open,
-                                               (cam->state & DEV_DISCONNECTED)
-                                                        || !cam->users);
-               down_read(&zc0301_dev_lock);
-               if (err)
-                       goto out;
-               if (cam->state & DEV_DISCONNECTED) {
-                       err = -ENODEV;
-                       goto out;
-               }
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = zc0301_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = zc0301_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       zc0301_empty_framequeues(cam);
-
-       DBG(3, "Video device %s is open",
-           video_device_node_name(cam->v4ldev));
-
-out:
-       mutex_unlock(&cam->open_mutex);
-       if (err)
-               kref_put(&cam->kref, zc0301_release_resources);
-       up_read(&zc0301_dev_lock);
-       return err;
-}
-
-
-static int zc0301_release(struct file *filp)
-{
-       struct zc0301_device* cam;
-
-       down_write(&zc0301_dev_lock);
-
-       cam = video_drvdata(filp);
-
-       zc0301_stop_transfer(cam);
-       zc0301_release_buffers(cam);
-       cam->users--;
-       wake_up_interruptible_nr(&cam->wait_open, 1);
-
-       DBG(3, "Video device %s closed",
-           video_device_node_name(cam->v4ldev));
-
-       kref_put(&cam->kref, zc0301_release_resources);
-
-       up_write(&zc0301_dev_lock);
-
-       return 0;
-}
-
-
-static ssize_t
-zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct zc0301_device *cam = video_drvdata(filp);
-       struct zc0301_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose the read "
-                      "method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EBUSY;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       zc0301_empty_framequeues(cam);
-               zc0301_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           msecs_to_jiffies(
-                               cam->module_param.frame_timeout * 1000
-                           )
-                         );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       zc0301_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err ? err : count;
-}
-
-
-static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
-{
-       struct zc0301_device *cam = video_drvdata(filp);
-       struct zc0301_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               zc0301_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void zc0301_vm_open(struct vm_area_struct* vma)
-{
-       struct zc0301_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void zc0301_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct zc0301_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct zc0301_vm_ops = {
-       .open = zc0301_vm_open,
-       .close = zc0301_vm_close,
-};
-
-
-static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct zc0301_device *cam = video_drvdata(filp);
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EACCES;
-       }
-
-       if (cam->io != IO_MMAP ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &zc0301_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-       zc0301_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "zc0301",
-               .version = ZC0301_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(s->qctrl))
-               return -EINVAL;
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       const enum zc0301_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EBUSY;
-                       }
-
-       if (!s->set_crop) {
-               memcpy(rect, &(s->_rect), sizeof(*rect));
-               if (copy_to_user(arg, &crop, sizeof(crop)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       rect->left &= ~7L;
-       rect->top &= ~7L;
-       if (rect->width < 8)
-               rect->width = 8;
-       if (rect->height < 8)
-               rect->height = 8;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-       rect->width &= ~7L;
-       rect->height &= ~7L;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               zc0301_release_buffers(cam);
-
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open %s again.",
-                   video_device_node_name(cam->v4ldev));
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width;
-       s->pix_format.height = rect->height;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open %s again.",
-                   video_device_node_name(cam->v4ldev));
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               zc0301_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               zc0301_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_frmsizeenum frmsize;
-
-       if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
-               return -EFAULT;
-
-       if (frmsize.index != 0 && frmsize.index != 1)
-               return -EINVAL;
-
-       if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
-               return -EINVAL;
-
-       frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
-       if (frmsize.index == 1) {
-               frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
-               frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
-       }
-       memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
-       if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "JPEG");
-               fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = 0;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
-                       void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       const enum zc0301_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       if (!s->set_crop) {
-               pix->width = rect.width;
-               pix->height = rect.height;
-       } else {
-               rect.width = pix->width;
-               rect.height = pix->height;
-       }
-
-       if (rect.width < 8)
-               rect.width = 8;
-       if (rect.height < 8)
-               rect.height = 8;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-       rect.width &= ~7L;
-       rect.height &= ~7L;
-
-       pix->width = rect.width;
-       pix->height = rect.height;
-       pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv;
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = 0;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. "
-                                      "Unmap the buffers first.");
-                               return -EBUSY;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               zc0301_release_buffers(cam);
-
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open %s again.",
-                   video_device_node_name(cam->v4ldev));
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open %s again.",
-                   video_device_node_name(cam->v4ldev));
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               zc0301_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               zc0301_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum zc0301_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       err += zc0301_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open %s again.",
-                      video_device_node_name(cam->v4ldev));
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EBUSY;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. "
-                              "Previous buffers are still mapped.");
-                       return -EBUSY;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       zc0301_empty_framequeues(cam);
-
-       zc0301_release_buffers(cam);
-       if (rb.count)
-               rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               zc0301_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
-                   void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct zc0301_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       zc0301_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
-               sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static long zc0301_ioctl_v4l2(struct file *filp,
-                            unsigned int cmd, void __user *arg)
-{
-       struct zc0301_device *cam = video_drvdata(filp);
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return zc0301_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return zc0301_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return zc0301_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return zc0301_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return zc0301_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return zc0301_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL:
-               return zc0301_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP:
-               return zc0301_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return zc0301_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return zc0301_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return zc0301_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return zc0301_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_ENUM_FRAMESIZES:
-               return zc0301_vidioc_enum_framesizes(cam, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return zc0301_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return zc0301_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return zc0301_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return zc0301_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return zc0301_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return zc0301_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return zc0301_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return zc0301_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return zc0301_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM:
-               return zc0301_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-       case VIDIOC_ENUM_FRAMEINTERVALS:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static long zc0301_ioctl(struct file *filp,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct zc0301_device *cam = video_drvdata(filp);
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "zc0301", cmd);
-
-       err = zc0301_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-
-static const struct v4l2_file_operations zc0301_fops = {
-       .owner =   THIS_MODULE,
-       .open =    zc0301_open,
-       .release = zc0301_release,
-       .ioctl =   zc0301_ioctl,
-       .read =    zc0301_read,
-       .poll =    zc0301_poll,
-       .mmap =    zc0301_mmap,
-};
-
-/*****************************************************************************/
-
-static int
-zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct zc0301_device* cam;
-       static unsigned int dev_nr;
-       unsigned int i;
-       int err = 0;
-
-       if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
-              "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
-
-       for  (i = 0; zc0301_sensor_table[i]; i++) {
-               err = zc0301_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err)
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-       else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (zc0301_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
-       cam->v4ldev->fops = &zc0301_fops;
-       cam->v4ldev->release = video_device_release;
-       cam->v4ldev->parent = &udev->dev;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       init_completion(&cam->probe);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               complete_all(&cam->probe);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as %s",
-           video_device_node_name(cam->v4ldev));
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-       usb_set_intfdata(intf, cam);
-       kref_init(&cam->kref);
-       usb_get_dev(cam->usbdev);
-
-       complete_all(&cam->probe);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void zc0301_usb_disconnect(struct usb_interface* intf)
-{
-       struct zc0301_device* cam;
-
-       down_write(&zc0301_dev_lock);
-
-       cam = usb_get_intfdata(intf);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       if (cam->users) {
-               DBG(2, "Device %s is open! Deregistration and "
-                      "memory deallocation are deferred.",
-                   video_device_node_name(cam->v4ldev));
-               cam->state |= DEV_MISCONFIGURED;
-               zc0301_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-       } else
-               cam->state |= DEV_DISCONNECTED;
-
-       wake_up_interruptible_all(&cam->wait_open);
-
-       kref_put(&cam->kref, zc0301_release_resources);
-
-       up_write(&zc0301_dev_lock);
-}
-
-
-static struct usb_driver zc0301_usb_driver = {
-       .name =       "zc0301",
-       .id_table =   zc0301_id_table,
-       .probe =      zc0301_usb_probe,
-       .disconnect = zc0301_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init zc0301_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
-       KDBG(3, ZC0301_MODULE_AUTHOR);
-
-       if ((err = usb_register(&zc0301_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit zc0301_module_exit(void)
-{
-       usb_deregister(&zc0301_usb_driver);
-}
-
-
-module_init(zc0301_module_init);
-module_exit(zc0301_module_exit);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
deleted file mode 100644 (file)
index 24b0dfb..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image        *
- * Processor and Control Chip                                              *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-/*
-   NOTE: Sensor controls are disabled for now, becouse changing them while
-        streaming sometimes results in out-of-sync video frames. We'll use
-        the default initialization, until we know how to stop and start video
-        in the chip. However, the image quality still looks good under various
-        light conditions.
-*/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct zc0301_device* cam)
-{
-       int err = 0;
-
-       err += zc0301_write_reg(cam, 0x0002, 0x00);
-       err += zc0301_write_reg(cam, 0x0003, 0x02);
-       err += zc0301_write_reg(cam, 0x0004, 0x80);
-       err += zc0301_write_reg(cam, 0x0005, 0x01);
-       err += zc0301_write_reg(cam, 0x0006, 0xE0);
-       err += zc0301_write_reg(cam, 0x0098, 0x00);
-       err += zc0301_write_reg(cam, 0x009A, 0x03);
-       err += zc0301_write_reg(cam, 0x011A, 0x00);
-       err += zc0301_write_reg(cam, 0x011C, 0x03);
-       err += zc0301_write_reg(cam, 0x009B, 0x01);
-       err += zc0301_write_reg(cam, 0x009C, 0xE6);
-       err += zc0301_write_reg(cam, 0x009D, 0x02);
-       err += zc0301_write_reg(cam, 0x009E, 0x86);
-
-       err += zc0301_i2c_write(cam, 0x02, 0x02);
-       err += zc0301_i2c_write(cam, 0x0A, 0x01);
-       err += zc0301_i2c_write(cam, 0x0B, 0x01);
-       err += zc0301_i2c_write(cam, 0x0D, 0x00);
-       err += zc0301_i2c_write(cam, 0x12, 0x05);
-       err += zc0301_i2c_write(cam, 0x13, 0x63);
-       err += zc0301_i2c_write(cam, 0x15, 0x70);
-
-       err += zc0301_write_reg(cam, 0x0101, 0xB7);
-       err += zc0301_write_reg(cam, 0x0100, 0x0D);
-       err += zc0301_write_reg(cam, 0x0189, 0x06);
-       err += zc0301_write_reg(cam, 0x01AD, 0x00);
-       err += zc0301_write_reg(cam, 0x01C5, 0x03);
-       err += zc0301_write_reg(cam, 0x01CB, 0x13);
-       err += zc0301_write_reg(cam, 0x0250, 0x08);
-       err += zc0301_write_reg(cam, 0x0301, 0x08);
-       err += zc0301_write_reg(cam, 0x018D, 0x70);
-       err += zc0301_write_reg(cam, 0x0008, 0x03);
-       err += zc0301_write_reg(cam, 0x01C6, 0x04);
-       err += zc0301_write_reg(cam, 0x01CB, 0x07);
-       err += zc0301_write_reg(cam, 0x0120, 0x11);
-       err += zc0301_write_reg(cam, 0x0121, 0x37);
-       err += zc0301_write_reg(cam, 0x0122, 0x58);
-       err += zc0301_write_reg(cam, 0x0123, 0x79);
-       err += zc0301_write_reg(cam, 0x0124, 0x91);
-       err += zc0301_write_reg(cam, 0x0125, 0xA6);
-       err += zc0301_write_reg(cam, 0x0126, 0xB8);
-       err += zc0301_write_reg(cam, 0x0127, 0xC7);
-       err += zc0301_write_reg(cam, 0x0128, 0xD3);
-       err += zc0301_write_reg(cam, 0x0129, 0xDE);
-       err += zc0301_write_reg(cam, 0x012A, 0xE6);
-       err += zc0301_write_reg(cam, 0x012B, 0xED);
-       err += zc0301_write_reg(cam, 0x012C, 0xF3);
-       err += zc0301_write_reg(cam, 0x012D, 0xF8);
-       err += zc0301_write_reg(cam, 0x012E, 0xFB);
-       err += zc0301_write_reg(cam, 0x012F, 0xFF);
-       err += zc0301_write_reg(cam, 0x0130, 0x26);
-       err += zc0301_write_reg(cam, 0x0131, 0x23);
-       err += zc0301_write_reg(cam, 0x0132, 0x20);
-       err += zc0301_write_reg(cam, 0x0133, 0x1C);
-       err += zc0301_write_reg(cam, 0x0134, 0x16);
-       err += zc0301_write_reg(cam, 0x0135, 0x13);
-       err += zc0301_write_reg(cam, 0x0136, 0x10);
-       err += zc0301_write_reg(cam, 0x0137, 0x0D);
-       err += zc0301_write_reg(cam, 0x0138, 0x0B);
-       err += zc0301_write_reg(cam, 0x0139, 0x09);
-       err += zc0301_write_reg(cam, 0x013A, 0x07);
-       err += zc0301_write_reg(cam, 0x013B, 0x06);
-       err += zc0301_write_reg(cam, 0x013C, 0x05);
-       err += zc0301_write_reg(cam, 0x013D, 0x04);
-       err += zc0301_write_reg(cam, 0x013E, 0x03);
-       err += zc0301_write_reg(cam, 0x013F, 0x02);
-       err += zc0301_write_reg(cam, 0x010A, 0x4C);
-       err += zc0301_write_reg(cam, 0x010B, 0xF5);
-       err += zc0301_write_reg(cam, 0x010C, 0xFF);
-       err += zc0301_write_reg(cam, 0x010D, 0xF9);
-       err += zc0301_write_reg(cam, 0x010E, 0x51);
-       err += zc0301_write_reg(cam, 0x010F, 0xF5);
-       err += zc0301_write_reg(cam, 0x0110, 0xFB);
-       err += zc0301_write_reg(cam, 0x0111, 0xED);
-       err += zc0301_write_reg(cam, 0x0112, 0x5F);
-       err += zc0301_write_reg(cam, 0x0180, 0x00);
-       err += zc0301_write_reg(cam, 0x0019, 0x00);
-       err += zc0301_write_reg(cam, 0x0087, 0x20);
-       err += zc0301_write_reg(cam, 0x0088, 0x21);
-
-       err += zc0301_i2c_write(cam, 0x20, 0x02);
-       err += zc0301_i2c_write(cam, 0x21, 0x1B);
-       err += zc0301_i2c_write(cam, 0x03, 0x44);
-       err += zc0301_i2c_write(cam, 0x0E, 0x01);
-       err += zc0301_i2c_write(cam, 0x0F, 0x00);
-
-       err += zc0301_write_reg(cam, 0x01A9, 0x14);
-       err += zc0301_write_reg(cam, 0x01AA, 0x24);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0191, 0x02);
-       err += zc0301_write_reg(cam, 0x0192, 0x1B);
-       err += zc0301_write_reg(cam, 0x0195, 0x00);
-       err += zc0301_write_reg(cam, 0x0196, 0x00);
-       err += zc0301_write_reg(cam, 0x0197, 0x4D);
-       err += zc0301_write_reg(cam, 0x018C, 0x10);
-       err += zc0301_write_reg(cam, 0x018F, 0x20);
-       err += zc0301_write_reg(cam, 0x001D, 0x44);
-       err += zc0301_write_reg(cam, 0x001E, 0x6F);
-       err += zc0301_write_reg(cam, 0x001F, 0xAD);
-       err += zc0301_write_reg(cam, 0x0020, 0xEB);
-       err += zc0301_write_reg(cam, 0x0087, 0x0F);
-       err += zc0301_write_reg(cam, 0x0088, 0x0E);
-       err += zc0301_write_reg(cam, 0x0180, 0x40);
-       err += zc0301_write_reg(cam, 0x0192, 0x1B);
-       err += zc0301_write_reg(cam, 0x0191, 0x02);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0116, 0x1D);
-       err += zc0301_write_reg(cam, 0x0117, 0x40);
-       err += zc0301_write_reg(cam, 0x0118, 0x99);
-       err += zc0301_write_reg(cam, 0x0180, 0x42);
-       err += zc0301_write_reg(cam, 0x0116, 0x1D);
-       err += zc0301_write_reg(cam, 0x0117, 0x40);
-       err += zc0301_write_reg(cam, 0x0118, 0x99);
-       err += zc0301_write_reg(cam, 0x0007, 0x00);
-
-       err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-       msleep(100);
-
-       return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct zc0301_device* cam,
-                             struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = zc0301_i2c_read(cam, 0x04, 1),
-                           r2 = zc0301_i2c_read(cam, 0x05, 1);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case ZC0301_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
-                       return -EIO;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas202bcb_set_ctrl(struct zc0301_device* cam,
-                             const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += zc0301_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += zc0301_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += zc0301_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case ZC0301_V4L2_CID_GREEN_BALANCE:
-               err += zc0301_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-               err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static struct zc0301_sensor pas202bcb = {
-       .name = "PAS202BCB",
-       .init = &pas202bcb_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-       },
-       .get_ctrl = &pas202bcb_get_ctrl,
-       .set_ctrl = &pas202bcb_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_JPEG,
-               .priv = 8,
-               .colorspace = V4L2_COLORSPACE_JPEG,
-       },
-};
-
-
-int zc0301_probe_pas202bcb(struct zc0301_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       err += zc0301_write_reg(cam, 0x0000, 0x01);
-       err += zc0301_write_reg(cam, 0x0010, 0x0e);
-       err += zc0301_write_reg(cam, 0x0001, 0x01);
-       err += zc0301_write_reg(cam, 0x0012, 0x03);
-       err += zc0301_write_reg(cam, 0x0012, 0x01);
-       err += zc0301_write_reg(cam, 0x008d, 0x08);
-
-       msleep(10);
-
-       r0 = zc0301_i2c_read(cam, 0x00, 1);
-       r1 = zc0301_i2c_read(cam, 0x01, 1);
-
-       if (r0 < 0 || r1 < 0 || err)
-               return -EIO;
-
-       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x017)
-               return -ENODEV;
-
-       zc0301_attach_sensor(cam, &pas202bcb);
-
-       return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
deleted file mode 100644 (file)
index 9519aba..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301P Image         *
- * Processor and Control Chip                                              *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pb0330;
-
-
-static int pb0330_init(struct zc0301_device* cam)
-{
-       int err = 0;
-
-       err += zc0301_write_reg(cam, 0x0000, 0x01);
-       err += zc0301_write_reg(cam, 0x0008, 0x03);
-       err += zc0301_write_reg(cam, 0x0010, 0x0A);
-       err += zc0301_write_reg(cam, 0x0002, 0x00);
-       err += zc0301_write_reg(cam, 0x0003, 0x02);
-       err += zc0301_write_reg(cam, 0x0004, 0x80);
-       err += zc0301_write_reg(cam, 0x0005, 0x01);
-       err += zc0301_write_reg(cam, 0x0006, 0xE0);
-       err += zc0301_write_reg(cam, 0x0001, 0x01);
-       err += zc0301_write_reg(cam, 0x0012, 0x05);
-       err += zc0301_write_reg(cam, 0x0012, 0x07);
-       err += zc0301_write_reg(cam, 0x0098, 0x00);
-       err += zc0301_write_reg(cam, 0x009A, 0x00);
-       err += zc0301_write_reg(cam, 0x011A, 0x00);
-       err += zc0301_write_reg(cam, 0x011C, 0x00);
-       err += zc0301_write_reg(cam, 0x0012, 0x05);
-
-       err += zc0301_i2c_write(cam, 0x01, 0x0006);
-       err += zc0301_i2c_write(cam, 0x02, 0x0011);
-       err += zc0301_i2c_write(cam, 0x03, 0x01E7);
-       err += zc0301_i2c_write(cam, 0x04, 0x0287);
-       err += zc0301_i2c_write(cam, 0x06, 0x0003);
-       err += zc0301_i2c_write(cam, 0x07, 0x3002);
-       err += zc0301_i2c_write(cam, 0x20, 0x1100);
-       err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
-       err += zc0301_i2c_write(cam, 0x30, 0x0005);
-       err += zc0301_i2c_write(cam, 0x31, 0x0000);
-       err += zc0301_i2c_write(cam, 0x34, 0x0100);
-       err += zc0301_i2c_write(cam, 0x35, 0x0060);
-       err += zc0301_i2c_write(cam, 0x3D, 0x068F);
-       err += zc0301_i2c_write(cam, 0x40, 0x01E0);
-       err += zc0301_i2c_write(cam, 0x58, 0x0078);
-       err += zc0301_i2c_write(cam, 0x62, 0x0411);
-
-       err += zc0301_write_reg(cam, 0x0087, 0x10);
-       err += zc0301_write_reg(cam, 0x0101, 0x37);
-       err += zc0301_write_reg(cam, 0x0012, 0x05);
-       err += zc0301_write_reg(cam, 0x0100, 0x0D);
-       err += zc0301_write_reg(cam, 0x0189, 0x06);
-       err += zc0301_write_reg(cam, 0x01AD, 0x00);
-       err += zc0301_write_reg(cam, 0x01C5, 0x03);
-       err += zc0301_write_reg(cam, 0x01CB, 0x13);
-       err += zc0301_write_reg(cam, 0x0250, 0x08);
-       err += zc0301_write_reg(cam, 0x0301, 0x08);
-       err += zc0301_write_reg(cam, 0x01A8, 0x60);
-       err += zc0301_write_reg(cam, 0x018D, 0x6C);
-       err += zc0301_write_reg(cam, 0x01AD, 0x09);
-       err += zc0301_write_reg(cam, 0x01AE, 0x15);
-       err += zc0301_write_reg(cam, 0x010A, 0x50);
-       err += zc0301_write_reg(cam, 0x010B, 0xF8);
-       err += zc0301_write_reg(cam, 0x010C, 0xF8);
-       err += zc0301_write_reg(cam, 0x010D, 0xF8);
-       err += zc0301_write_reg(cam, 0x010E, 0x50);
-       err += zc0301_write_reg(cam, 0x010F, 0xF8);
-       err += zc0301_write_reg(cam, 0x0110, 0xF8);
-       err += zc0301_write_reg(cam, 0x0111, 0xF8);
-       err += zc0301_write_reg(cam, 0x0112, 0x50);
-       err += zc0301_write_reg(cam, 0x0008, 0x03);
-       err += zc0301_write_reg(cam, 0x01C6, 0x08);
-       err += zc0301_write_reg(cam, 0x01CB, 0x0F);
-       err += zc0301_write_reg(cam, 0x010A, 0x50);
-       err += zc0301_write_reg(cam, 0x010B, 0xF8);
-       err += zc0301_write_reg(cam, 0x010C, 0xF8);
-       err += zc0301_write_reg(cam, 0x010D, 0xF8);
-       err += zc0301_write_reg(cam, 0x010E, 0x50);
-       err += zc0301_write_reg(cam, 0x010F, 0xF8);
-       err += zc0301_write_reg(cam, 0x0110, 0xF8);
-       err += zc0301_write_reg(cam, 0x0111, 0xF8);
-       err += zc0301_write_reg(cam, 0x0112, 0x50);
-       err += zc0301_write_reg(cam, 0x0180, 0x00);
-       err += zc0301_write_reg(cam, 0x0019, 0x00);
-
-       err += zc0301_i2c_write(cam, 0x05, 0x0066);
-       err += zc0301_i2c_write(cam, 0x09, 0x02B2);
-       err += zc0301_i2c_write(cam, 0x10, 0x0002);
-
-       err += zc0301_write_reg(cam, 0x011D, 0x60);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0191, 0x07);
-       err += zc0301_write_reg(cam, 0x0192, 0x8C);
-       err += zc0301_write_reg(cam, 0x0195, 0x00);
-       err += zc0301_write_reg(cam, 0x0196, 0x00);
-       err += zc0301_write_reg(cam, 0x0197, 0x8A);
-       err += zc0301_write_reg(cam, 0x018C, 0x10);
-       err += zc0301_write_reg(cam, 0x018F, 0x20);
-       err += zc0301_write_reg(cam, 0x01A9, 0x14);
-       err += zc0301_write_reg(cam, 0x01AA, 0x24);
-       err += zc0301_write_reg(cam, 0x001D, 0xD7);
-       err += zc0301_write_reg(cam, 0x001E, 0xF0);
-       err += zc0301_write_reg(cam, 0x001F, 0xF8);
-       err += zc0301_write_reg(cam, 0x0020, 0xFF);
-       err += zc0301_write_reg(cam, 0x01AD, 0x09);
-       err += zc0301_write_reg(cam, 0x01AE, 0x15);
-       err += zc0301_write_reg(cam, 0x0180, 0x40);
-       err += zc0301_write_reg(cam, 0x0180, 0x42);
-
-       msleep(100);
-
-       return err;
-}
-
-
-static struct zc0301_sensor pb0330 = {
-       .name = "PB-0330",
-       .init = &pb0330_init,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_JPEG,
-               .priv = 8,
-               .colorspace = V4L2_COLORSPACE_JPEG,
-       },
-};
-
-
-int zc0301_probe_pb0330(struct zc0301_device* cam)
-{
-       int r0, err = 0;
-
-       err += zc0301_write_reg(cam, 0x0000, 0x01);
-       err += zc0301_write_reg(cam, 0x0010, 0x0a);
-       err += zc0301_write_reg(cam, 0x0001, 0x01);
-       err += zc0301_write_reg(cam, 0x0012, 0x03);
-       err += zc0301_write_reg(cam, 0x0012, 0x01);
-
-       msleep(10);
-
-       r0 = zc0301_i2c_read(cam, 0x00, 2);
-
-       if (r0 < 0 || err)
-               return -EIO;
-
-       if (r0 != 0x8243)
-               return -ENODEV;
-
-       zc0301_attach_sensor(cam, &pb0330);
-
-       return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
deleted file mode 100644 (file)
index 0be783c..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the ZC0301[P] Image Processor and    *
- * Control Chip                                                            *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; 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 _ZC0301_SENSOR_H_
-#define _ZC0301_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct zc0301_device;
-struct zc0301_sensor;
-
-/*****************************************************************************/
-
-extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
-extern int zc0301_probe_pb0330(struct zc0301_device* cam);
-
-#define ZC0301_SENSOR_TABLE                                                   \
-/* Weak detections must go at the end of the list */                          \
-static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
-       &zc0301_probe_pas202bcb,                                              \
-       &zc0301_probe_pb0330,                                                 \
-       NULL,                                                                 \
-};
-
-extern struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
-
-extern void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
-
-#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-       .idVendor = (vend),                                                   \
-       .idProduct = (prod),                                                  \
-       .bInterfaceClass = (intclass)
-
-#if !defined CONFIG_USB_GSPCA_ZC3XX && !defined CONFIG_USB_GSPCA_ZC3XX_MODULE
-#define ZC0301_ID_TABLE                                                       \
-static const struct usb_device_id zc0301_id_table[] =  {                      \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
-       { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
-       { }                                                                   \
-};
-#else
-#define ZC0301_ID_TABLE                                                       \
-static const struct usb_device_id zc0301_id_table[] =  {                      \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
-       { }                                                                   \
-};
-#endif
-
-/*****************************************************************************/
-
-extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
-extern int zc0301_read_reg(struct zc0301_device*, u16 index);
-extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
-extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
-
-/*****************************************************************************/
-
-#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
-#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
-
-struct zc0301_sensor {
-       char name[32];
-
-       struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
-       struct v4l2_cropcap cropcap;
-       struct v4l2_pix_format pix_format;
-
-       int (*init)(struct zc0301_device*);
-       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct zc0301_device*,
-                       const struct v4l2_control* ctrl);
-       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
-
-       /* Private */
-       struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-#endif /* _ZC0301_SENSOR_H_ */
index cf24956f3204272cd6b9eeebb5ecf7b8c20ffeaa..c010716352903e3000ea56278df4edc290a7b320 100644 (file)
@@ -107,15 +107,14 @@ videocodec_attach (struct videocodec_master *master)
                        if (!try_module_get(h->codec->owner))
                                return NULL;
 
-                       codec =
-                           kmalloc(sizeof(struct videocodec), GFP_KERNEL);
+                       codec = kmemdup(h->codec, sizeof(struct videocodec),
+                                       GFP_KERNEL);
                        if (!codec) {
                                dprintk(1,
                                        KERN_ERR
                                        "videocodec_attach: no mem\n");
                                goto out_module_put;
                        }
-                       memcpy(codec, h->codec, sizeof(struct videocodec));
 
                        snprintf(codec->name, sizeof(codec->name),
                                 "%s[%d]", codec->name, h->attached);
index 26386a92f5aafbb614c3308d7c03c05f638cfc15..9b089dfb173ef987f5220d38bce0336c66b92a0f 100644 (file)
@@ -353,6 +353,16 @@ config VMWARE_BALLOON
          To compile this driver as a module, choose M here: the
          module will be called vmware_balloon.
 
+config ARM_CHARLCD
+       bool "ARM Ltd. Character LCD Driver"
+       depends on PLAT_VERSATILE
+       help
+         This is a driver for the character LCD found on the ARM Ltd.
+         Versatile and RealView Platform Baseboards. It doesn't do
+         very much more than display the text "ARM Linux" on the first
+         line and the Linux version on the second line, but that's
+         still useful.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index 6ed06a19474acc23de3b93b732ecce25b9a55c40..67552d6e932784b2e8c19e8f0c840483a52faa65 100644 (file)
@@ -31,3 +31,4 @@ obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
 obj-y                          += eeprom/
 obj-y                          += cb710/
 obj-$(CONFIG_VMWARE_BALLOON)   += vmware_balloon.o
+obj-$(CONFIG_ARM_CHARLCD)      += arm-charlcd.o
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c
new file mode 100644 (file)
index 0000000..9e3879e
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Driver for the on-board character LCD found on some ARM reference boards
+ * This is basically an Hitachi HD44780 LCD with a custom IP block to drive it
+ * http://en.wikipedia.org/wiki/HD44780_Character_LCD
+ * Currently it will just display the text "ARM Linux" and the linux version
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Linus Walleij <triad@df.lth.se>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <generated/utsrelease.h>
+
+#define DRIVERNAME "arm-charlcd"
+#define CHARLCD_TIMEOUT (msecs_to_jiffies(1000))
+
+/* Offsets to registers */
+#define CHAR_COM       0x00U
+#define CHAR_DAT       0x04U
+#define CHAR_RD                0x08U
+#define CHAR_RAW       0x0CU
+#define CHAR_MASK      0x10U
+#define CHAR_STAT      0x14U
+
+#define CHAR_RAW_CLEAR 0x00000000U
+#define CHAR_RAW_VALID 0x00000100U
+
+/* Hitachi HD44780 display commands */
+#define HD_CLEAR                       0x01U
+#define HD_HOME                                0x02U
+#define HD_ENTRYMODE                   0x04U
+#define HD_ENTRYMODE_INCREMENT         0x02U
+#define HD_ENTRYMODE_SHIFT             0x01U
+#define HD_DISPCTRL                    0x08U
+#define HD_DISPCTRL_ON                 0x04U
+#define HD_DISPCTRL_CURSOR_ON          0x02U
+#define HD_DISPCTRL_CURSOR_BLINK       0x01U
+#define HD_CRSR_SHIFT                  0x10U
+#define HD_CRSR_SHIFT_DISPLAY          0x08U
+#define HD_CRSR_SHIFT_DISPLAY_RIGHT    0x04U
+#define HD_FUNCSET                     0x20U
+#define HD_FUNCSET_8BIT                        0x10U
+#define HD_FUNCSET_2_LINES             0x08U
+#define HD_FUNCSET_FONT_5X10           0x04U
+#define HD_SET_CGRAM                   0x40U
+#define HD_SET_DDRAM                   0x80U
+#define HD_BUSY_FLAG                   0x80U
+
+/**
+ * @dev: a pointer back to containing device
+ * @phybase: the offset to the controller in physical memory
+ * @physize: the size of the physical page
+ * @virtbase: the offset to the controller in virtual memory
+ * @irq: reserved interrupt number
+ * @complete: completion structure for the last LCD command
+ */
+struct charlcd {
+       struct device *dev;
+       u32 phybase;
+       u32 physize;
+       void __iomem *virtbase;
+       int irq;
+       struct completion complete;
+       struct delayed_work init_work;
+};
+
+static irqreturn_t charlcd_interrupt(int irq, void *data)
+{
+       struct charlcd *lcd = data;
+       u8 status;
+
+       status = readl(lcd->virtbase + CHAR_STAT) & 0x01;
+       /* Clear IRQ */
+       writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+       if (status)
+               complete(&lcd->complete);
+       else
+               dev_info(lcd->dev, "Spurious IRQ (%02x)\n", status);
+       return IRQ_HANDLED;
+}
+
+
+static void charlcd_wait_complete_irq(struct charlcd *lcd)
+{
+       int ret;
+
+       ret = wait_for_completion_interruptible_timeout(&lcd->complete,
+                                                       CHARLCD_TIMEOUT);
+       /* Disable IRQ after completion */
+       writel(0x00, lcd->virtbase + CHAR_MASK);
+
+       if (ret < 0) {
+               dev_err(lcd->dev,
+                       "wait_for_completion_interruptible_timeout() "
+                       "returned %d waiting for ready\n", ret);
+               return;
+       }
+
+       if (ret == 0) {
+               dev_err(lcd->dev, "charlcd controller timed out "
+                       "waiting for ready\n");
+               return;
+       }
+}
+
+static u8 charlcd_4bit_read_char(struct charlcd *lcd)
+{
+       u8 data;
+       u32 val;
+       int i;
+
+       /* If we can, use an IRQ to wait for the data, else poll */
+       if (lcd->irq >= 0)
+               charlcd_wait_complete_irq(lcd);
+       else {
+               i = 0;
+               val = 0;
+               while (!(val & CHAR_RAW_VALID) && i < 10) {
+                       udelay(100);
+                       val = readl(lcd->virtbase + CHAR_RAW);
+                       i++;
+               }
+
+               writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+       }
+       msleep(1);
+
+       /* Read the 4 high bits of the data */
+       data = readl(lcd->virtbase + CHAR_RD) & 0xf0;
+
+       /*
+        * The second read for the low bits does not trigger an IRQ
+        * so in this case we have to poll for the 4 lower bits
+        */
+       i = 0;
+       val = 0;
+       while (!(val & CHAR_RAW_VALID) && i < 10) {
+               udelay(100);
+               val = readl(lcd->virtbase + CHAR_RAW);
+               i++;
+       }
+       writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+       msleep(1);
+
+       /* Read the 4 low bits of the data */
+       data |= (readl(lcd->virtbase + CHAR_RD) >> 4) & 0x0f;
+
+       return data;
+}
+
+static bool charlcd_4bit_read_bf(struct charlcd *lcd)
+{
+       if (lcd->irq >= 0) {
+               /*
+                * If we'll use IRQs to wait for the busyflag, clear any
+                * pending flag and enable IRQ
+                */
+               writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+               init_completion(&lcd->complete);
+               writel(0x01, lcd->virtbase + CHAR_MASK);
+       }
+       readl(lcd->virtbase + CHAR_COM);
+       return charlcd_4bit_read_char(lcd) & HD_BUSY_FLAG ? true : false;
+}
+
+static void charlcd_4bit_wait_busy(struct charlcd *lcd)
+{
+       int retries = 50;
+
+       udelay(100);
+       while (charlcd_4bit_read_bf(lcd) && retries)
+               retries--;
+       if (!retries)
+               dev_err(lcd->dev, "timeout waiting for busyflag\n");
+}
+
+static void charlcd_4bit_command(struct charlcd *lcd, u8 cmd)
+{
+       u32 cmdlo = (cmd << 4) & 0xf0;
+       u32 cmdhi = (cmd & 0xf0);
+
+       writel(cmdhi, lcd->virtbase + CHAR_COM);
+       udelay(10);
+       writel(cmdlo, lcd->virtbase + CHAR_COM);
+       charlcd_4bit_wait_busy(lcd);
+}
+
+static void charlcd_4bit_char(struct charlcd *lcd, u8 ch)
+{
+       u32 chlo = (ch << 4) & 0xf0;
+       u32 chhi = (ch & 0xf0);
+
+       writel(chhi, lcd->virtbase + CHAR_DAT);
+       udelay(10);
+       writel(chlo, lcd->virtbase + CHAR_DAT);
+       charlcd_4bit_wait_busy(lcd);
+}
+
+static void charlcd_4bit_print(struct charlcd *lcd, int line, const char *str)
+{
+       u8 offset;
+       int i;
+
+       /*
+        * We support line 0, 1
+        * Line 1 runs from 0x00..0x27
+        * Line 2 runs from 0x28..0x4f
+        */
+       if (line == 0)
+               offset = 0;
+       else if (line == 1)
+               offset = 0x28;
+       else
+               return;
+
+       /* Set offset */
+       charlcd_4bit_command(lcd, HD_SET_DDRAM | offset);
+
+       /* Send string */
+       for (i = 0; i < strlen(str) && i < 0x28; i++)
+               charlcd_4bit_char(lcd, str[i]);
+}
+
+static void charlcd_4bit_init(struct charlcd *lcd)
+{
+       /* These commands cannot be checked with the busy flag */
+       writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
+       msleep(5);
+       writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
+       udelay(100);
+       writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
+       udelay(100);
+       /* Go to 4bit mode */
+       writel(HD_FUNCSET, lcd->virtbase + CHAR_COM);
+       udelay(100);
+       /*
+        * 4bit mode, 2 lines, 5x8 font, after this the number of lines
+        * and the font cannot be changed until the next initialization sequence
+        */
+       charlcd_4bit_command(lcd, HD_FUNCSET | HD_FUNCSET_2_LINES);
+       charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
+       charlcd_4bit_command(lcd, HD_ENTRYMODE | HD_ENTRYMODE_INCREMENT);
+       charlcd_4bit_command(lcd, HD_CLEAR);
+       charlcd_4bit_command(lcd, HD_HOME);
+       /* Put something useful in the display */
+       charlcd_4bit_print(lcd, 0, "ARM Linux");
+       charlcd_4bit_print(lcd, 1, UTS_RELEASE);
+}
+
+static void charlcd_init_work(struct work_struct *work)
+{
+       struct charlcd *lcd =
+               container_of(work, struct charlcd, init_work.work);
+
+       charlcd_4bit_init(lcd);
+}
+
+static int __init charlcd_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct charlcd *lcd;
+       struct resource *res;
+
+       lcd = kzalloc(sizeof(struct charlcd), GFP_KERNEL);
+       if (!lcd)
+               return -ENOMEM;
+
+       lcd->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENOENT;
+               goto out_no_resource;
+       }
+       lcd->phybase = res->start;
+       lcd->physize = resource_size(res);
+
+       if (request_mem_region(lcd->phybase, lcd->physize,
+                              DRIVERNAME) == NULL) {
+               ret = -EBUSY;
+               goto out_no_memregion;
+       }
+
+       lcd->virtbase = ioremap(lcd->phybase, lcd->physize);
+       if (!lcd->virtbase) {
+               ret = -ENOMEM;
+               goto out_no_remap;
+       }
+
+       lcd->irq = platform_get_irq(pdev, 0);
+       /* If no IRQ is supplied, we'll survive without it */
+       if (lcd->irq >= 0) {
+               if (request_irq(lcd->irq, charlcd_interrupt, IRQF_DISABLED,
+                               DRIVERNAME, lcd)) {
+                       ret = -EIO;
+                       goto out_no_irq;
+               }
+       }
+
+       platform_set_drvdata(pdev, lcd);
+
+       /*
+        * Initialize the display in a delayed work, because
+        * it is VERY slow and would slow down the boot of the system.
+        */
+       INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work);
+       schedule_delayed_work(&lcd->init_work, 0);
+
+       dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n",
+               lcd->phybase);
+
+       return 0;
+
+out_no_irq:
+       iounmap(lcd->virtbase);
+out_no_remap:
+       platform_set_drvdata(pdev, NULL);
+out_no_memregion:
+       release_mem_region(lcd->phybase, SZ_4K);
+out_no_resource:
+       kfree(lcd);
+       return ret;
+}
+
+static int __exit charlcd_remove(struct platform_device *pdev)
+{
+       struct charlcd *lcd = platform_get_drvdata(pdev);
+
+       if (lcd) {
+               free_irq(lcd->irq, lcd);
+               iounmap(lcd->virtbase);
+               release_mem_region(lcd->phybase, lcd->physize);
+               platform_set_drvdata(pdev, NULL);
+               kfree(lcd);
+       }
+
+       return 0;
+}
+
+static int charlcd_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct charlcd *lcd = platform_get_drvdata(pdev);
+
+       /* Power the display off */
+       charlcd_4bit_command(lcd, HD_DISPCTRL);
+       return 0;
+}
+
+static int charlcd_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct charlcd *lcd = platform_get_drvdata(pdev);
+
+       /* Turn the display back on */
+       charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
+       return 0;
+}
+
+static const struct dev_pm_ops charlcd_pm_ops = {
+       .suspend = charlcd_suspend,
+       .resume = charlcd_resume,
+};
+
+static struct platform_driver charlcd_driver = {
+       .driver = {
+               .name = DRIVERNAME,
+               .owner = THIS_MODULE,
+               .pm = &charlcd_pm_ops,
+       },
+       .remove = __exit_p(charlcd_remove),
+};
+
+static int __init charlcd_init(void)
+{
+       return platform_driver_probe(&charlcd_driver, charlcd_probe);
+}
+
+static void __exit charlcd_exit(void)
+{
+       platform_driver_unregister(&charlcd_driver);
+}
+
+module_init(charlcd_init);
+module_exit(charlcd_exit);
+
+MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>");
+MODULE_DESCRIPTION("ARM Character LCD Driver");
+MODULE_LICENSE("GPL v2");
index 4917af96bae1d0be7472e32bf13784ec5ffb4412..840b301b567142b4e264924a14feb91c5cb54003 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/amba/mmci.h>
 #include <linux/regulator/consumer.h>
 
-#include <asm/cacheflush.h>
 #include <asm/div64.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
 
 static unsigned int fmax = 515633;
 
+/**
+ * struct variant_data - MMCI variant-specific quirks
+ * @clkreg: default value for MCICLOCK register
+ * @clkreg_enable: enable value for MMCICLOCK register
+ * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ */
+struct variant_data {
+       unsigned int            clkreg;
+       unsigned int            clkreg_enable;
+       unsigned int            datalength_bits;
+};
+
+static struct variant_data variant_arm = {
+       .datalength_bits        = 16,
+};
+
+static struct variant_data variant_u300 = {
+       .clkreg_enable          = 1 << 13, /* HWFCEN */
+       .datalength_bits        = 16,
+};
+
+static struct variant_data variant_ux500 = {
+       .clkreg                 = MCI_CLK_ENABLE,
+       .clkreg_enable          = 1 << 14, /* HWFCEN */
+       .datalength_bits        = 24,
+};
 /*
  * This must be called with host->lock held
  */
 static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 {
-       u32 clk = 0;
+       struct variant_data *variant = host->variant;
+       u32 clk = variant->clkreg;
 
        if (desired) {
                if (desired >= host->mclk) {
@@ -54,8 +80,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
                                clk = 255;
                        host->cclk = host->mclk / (2 * (clk + 1));
                }
-               if (host->hw_designer == AMBA_VENDOR_ST)
-                       clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */
+
+               clk |= variant->clkreg_enable;
                clk |= MCI_CLK_ENABLE;
                /* This hasn't proven to be worthwhile */
                /* clk |= MCI_CLK_PWRSAVE; */
@@ -98,6 +124,18 @@ static void mmci_stop_data(struct mmci_host *host)
        host->data = NULL;
 }
 
+static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+       unsigned int flags = SG_MITER_ATOMIC;
+
+       if (data->flags & MMC_DATA_READ)
+               flags |= SG_MITER_TO_SG;
+       else
+               flags |= SG_MITER_FROM_SG;
+
+       sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+}
+
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
        unsigned int datactrl, timeout, irqmask;
@@ -109,7 +147,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                data->blksz, data->blocks, data->flags);
 
        host->data = data;
-       host->size = data->blksz;
+       host->size = data->blksz * data->blocks;
        host->data_xfered = 0;
 
        mmci_init_sg(host, data);
@@ -210,8 +248,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                 * We hit an error condition.  Ensure that any data
                 * partially written to a page is properly coherent.
                 */
-               if (host->sg_len && data->flags & MMC_DATA_READ)
-                       flush_dcache_page(sg_page(host->sg_ptr));
+               if (data->flags & MMC_DATA_READ) {
+                       struct sg_mapping_iter *sg_miter = &host->sg_miter;
+                       unsigned long flags;
+
+                       local_irq_save(flags);
+                       if (sg_miter_next(sg_miter)) {
+                               flush_dcache_page(sg_miter->page);
+                               sg_miter_stop(sg_miter);
+                       }
+                       local_irq_restore(flags);
+               }
        }
        if (status & MCI_DATAEND) {
                mmci_stop_data(host);
@@ -314,15 +361,18 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
 static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
+       struct sg_mapping_iter *sg_miter = &host->sg_miter;
        void __iomem *base = host->base;
+       unsigned long flags;
        u32 status;
 
        status = readl(base + MMCISTATUS);
 
        dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
 
+       local_irq_save(flags);
+
        do {
-               unsigned long flags;
                unsigned int remain, len;
                char *buffer;
 
@@ -336,11 +386,11 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
                if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
                        break;
 
-               /*
-                * Map the current scatter buffer.
-                */
-               buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
-               remain = host->sg_ptr->length - host->sg_off;
+               if (!sg_miter_next(sg_miter))
+                       break;
+
+               buffer = sg_miter->addr;
+               remain = sg_miter->length;
 
                len = 0;
                if (status & MCI_RXACTIVE)
@@ -348,31 +398,24 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
                if (status & MCI_TXACTIVE)
                        len = mmci_pio_write(host, buffer, remain, status);
 
-               /*
-                * Unmap the buffer.
-                */
-               mmci_kunmap_atomic(host, buffer, &flags);
+               sg_miter->consumed = len;
 
-               host->sg_off += len;
                host->size -= len;
                remain -= len;
 
                if (remain)
                        break;
 
-               /*
-                * If we were reading, and we have completed this
-                * page, ensure that the data cache is coherent.
-                */
                if (status & MCI_RXACTIVE)
-                       flush_dcache_page(sg_page(host->sg_ptr));
-
-               if (!mmci_next_sg(host))
-                       break;
+                       flush_dcache_page(sg_miter->page);
 
                status = readl(base + MMCISTATUS);
        } while (1);
 
+       sg_miter_stop(sg_miter);
+
+       local_irq_restore(flags);
+
        /*
         * If we're nearing the end of the read, switch to
         * "any data available" mode.
@@ -477,16 +520,9 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        /* This implicitly enables the regulator */
                        mmc_regulator_set_ocr(host->vcc, ios->vdd);
 #endif
-               /*
-                * The translate_vdd function is not used if you have
-                * an external regulator, or your design is really weird.
-                * Using it would mean sending in power control BOTH using
-                * a regulator AND the 4 MMCIPWR bits. If we don't have
-                * a regulator, we might have some other platform specific
-                * power control behind this translate function.
-                */
-               if (!host->vcc && host->plat->translate_vdd)
-                       pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
+               if (host->plat->vdd_handler)
+                       pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
+                                                      ios->power_mode);
                /* The ST version does not have this, fall through to POWER_ON */
                if (host->hw_designer != AMBA_VENDOR_ST) {
                        pwr |= MCI_PWR_UP;
@@ -539,9 +575,13 @@ static int mmci_get_cd(struct mmc_host *mmc)
        if (host->gpio_cd == -ENOSYS)
                status = host->plat->status(mmc_dev(host->mmc));
        else
-               status = gpio_get_value(host->gpio_cd);
+               status = !gpio_get_value(host->gpio_cd);
 
-       return !status;
+       /*
+        * Use positive logic throughout - status is zero for no card,
+        * non-zero for card inserted.
+        */
+       return status;
 }
 
 static const struct mmc_host_ops mmci_ops = {
@@ -551,21 +591,10 @@ static const struct mmc_host_ops mmci_ops = {
        .get_cd         = mmci_get_cd,
 };
 
-static void mmci_check_status(unsigned long data)
-{
-       struct mmci_host *host = (struct mmci_host *)data;
-       unsigned int status = mmci_get_cd(host->mmc);
-
-       if (status ^ host->oldstat)
-               mmc_detect_change(host->mmc, 0);
-
-       host->oldstat = status;
-       mod_timer(&host->timer, jiffies + HZ);
-}
-
 static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 {
        struct mmci_platform_data *plat = dev->dev.platform_data;
+       struct variant_data *variant = id->data;
        struct mmci_host *host;
        struct mmc_host *mmc;
        int ret;
@@ -609,6 +638,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                goto clk_free;
 
        host->plat = plat;
+       host->variant = variant;
        host->mclk = clk_get_rate(host->clk);
        /*
         * According to the spec, mclk is max 100 MHz,
@@ -669,6 +699,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        if (host->vcc == NULL)
                mmc->ocr_avail = plat->ocr_mask;
        mmc->caps = plat->capabilities;
+       mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /*
         * We can do SGIO
@@ -677,10 +708,11 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        mmc->max_phys_segs = NR_SG;
 
        /*
-        * Since we only have a 16-bit data length register, we must
-        * ensure that we don't exceed 2^16-1 bytes in a single request.
+        * Since only a certain number of bits are valid in the data length
+        * register, we must ensure that we don't exceed 2^num-1 bytes in a
+        * single request.
         */
-       mmc->max_req_size = 65535;
+       mmc->max_req_size = (1 << variant->datalength_bits) - 1;
 
        /*
         * Set the maximum segment size.  Since we aren't doing DMA
@@ -734,7 +766,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        writel(MCI_IRQENABLE, host->base + MMCIMASK0);
 
        amba_set_drvdata(dev, mmc);
-       host->oldstat = mmci_get_cd(host->mmc);
 
        mmc_add_host(mmc);
 
@@ -742,12 +773,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
                (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
 
-       init_timer(&host->timer);
-       host->timer.data = (unsigned long)host;
-       host->timer.function = mmci_check_status;
-       host->timer.expires = jiffies + HZ;
-       add_timer(&host->timer);
-
        return 0;
 
  irq0_free:
@@ -781,8 +806,6 @@ static int __devexit mmci_remove(struct amba_device *dev)
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
 
-               del_timer_sync(&host->timer);
-
                mmc_remove_host(mmc);
 
                writel(0, host->base + MMCIMASK0);
@@ -856,19 +879,28 @@ static struct amba_id mmci_ids[] = {
        {
                .id     = 0x00041180,
                .mask   = 0x000fffff,
+               .data   = &variant_arm,
        },
        {
                .id     = 0x00041181,
                .mask   = 0x000fffff,
+               .data   = &variant_arm,
        },
        /* ST Micro variants */
        {
                .id     = 0x00180180,
                .mask   = 0x00ffffff,
+               .data   = &variant_u300,
        },
        {
                .id     = 0x00280180,
                .mask   = 0x00ffffff,
+               .data   = &variant_u300,
+       },
+       {
+               .id     = 0x00480180,
+               .mask   = 0x00ffffff,
+               .data   = &variant_ux500,
        },
        { 0, 0 },
 };
index d77062e5e3af5425b15d31c6609aafa784ddeff3..68970cfb81e1396ca9f5a3f817e4c7ede777d6ea 100644 (file)
@@ -28,8 +28,6 @@
 #define MCI_4BIT_BUS           (1 << 11)
 /* 8bit wide buses supported in ST Micro versions */
 #define MCI_ST_8BIT_BUS                (1 << 12)
-/* HW flow control on the ST Micro version */
-#define MCI_ST_FCEN            (1 << 13)
 
 #define MMCIARGUMENT           0x008
 #define MMCICOMMAND            0x00c
 #define NR_SG          16
 
 struct clk;
+struct variant_data;
 
 struct mmci_host {
        void __iomem            *base;
@@ -164,6 +163,7 @@ struct mmci_host {
        unsigned int            cclk;
        u32                     pwr;
        struct mmci_platform_data *plat;
+       struct variant_data     *variant;
 
        u8                      hw_designer;
        u8                      hw_revision:4;
@@ -171,42 +171,9 @@ struct mmci_host {
        struct timer_list       timer;
        unsigned int            oldstat;
 
-       unsigned int            sg_len;
-
        /* pio stuff */
-       struct scatterlist      *sg_ptr;
-       unsigned int            sg_off;
+       struct sg_mapping_iter  sg_miter;
        unsigned int            size;
        struct regulator        *vcc;
 };
 
-static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
-       /*
-        * Ideally, we want the higher levels to pass us a scatter list.
-        */
-       host->sg_len = data->sg_len;
-       host->sg_ptr = data->sg;
-       host->sg_off = 0;
-}
-
-static inline int mmci_next_sg(struct mmci_host *host)
-{
-       host->sg_ptr++;
-       host->sg_off = 0;
-       return --host->sg_len;
-}
-
-static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
-{
-       struct scatterlist *sg = host->sg_ptr;
-
-       local_irq_save(*flags);
-       return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
-{
-       kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
-       local_irq_restore(*flags);
-}
index d9d4a72e0ec792d42386d21afcf327fa5b59f69c..350f78e8624511cfd1378c4b8365a2d6d956a4ae 100644 (file)
@@ -119,6 +119,7 @@ struct mxcmci_host {
        int                     detect_irq;
        int                     dma;
        int                     do_dma;
+       int                     default_irq_mask;
        int                     use_sdio;
        unsigned int            power_mode;
        struct imxmmc_platform_data *pdata;
@@ -228,7 +229,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
                unsigned int cmdat)
 {
-       u32 int_cntr;
+       u32 int_cntr = host->default_irq_mask;
        unsigned long flags;
 
        WARN_ON(host->cmd != NULL);
@@ -275,7 +276,7 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
 static void mxcmci_finish_request(struct mxcmci_host *host,
                struct mmc_request *req)
 {
-       u32 int_cntr = 0;
+       u32 int_cntr = host->default_irq_mask;
        unsigned long flags;
 
        spin_lock_irqsave(&host->lock, flags);
@@ -585,6 +586,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
                  (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;
 }
 
@@ -809,6 +813,12 @@ static int mxcmci_probe(struct platform_device *pdev)
        else
                mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
+       if (host->pdata && host->pdata->dat3_card_detect)
+               host->default_irq_mask =
+                       INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN;
+       else
+               host->default_irq_mask = 0;
+
        host->res = r;
        host->irq = irq;
 
@@ -835,7 +845,7 @@ static int mxcmci_probe(struct platform_device *pdev)
        /* recommended in data sheet */
        writew(0x2db4, host->base + MMC_REG_READ_TO);
 
-       writel(0, host->base + MMC_REG_INT_CNTR);
+       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);
@@ -926,43 +936,47 @@ static int mxcmci_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int mxcmci_suspend(struct platform_device *dev, pm_message_t state)
+static int mxcmci_suspend(struct device *dev)
 {
-       struct mmc_host *mmc = platform_get_drvdata(dev);
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct mxcmci_host *host = mmc_priv(mmc);
        int ret = 0;
 
        if (mmc)
                ret = mmc_suspend_host(mmc);
+       clk_disable(host->clk);
 
        return ret;
 }
 
-static int mxcmci_resume(struct platform_device *dev)
+static int mxcmci_resume(struct device *dev)
 {
-       struct mmc_host *mmc = platform_get_drvdata(dev);
-       struct mxcmci_host *host;
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct mxcmci_host *host = mmc_priv(mmc);
        int ret = 0;
 
-       if (mmc) {
-               host = mmc_priv(mmc);
+       clk_enable(host->clk);
+       if (mmc)
                ret = mmc_resume_host(mmc);
-       }
 
        return ret;
 }
-#else
-#define mxcmci_suspend  NULL
-#define mxcmci_resume   NULL
-#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mxcmci_pm_ops = {
+       .suspend        = mxcmci_suspend,
+       .resume         = mxcmci_resume,
+};
+#endif
 
 static struct platform_driver mxcmci_driver = {
        .probe          = mxcmci_probe,
        .remove         = mxcmci_remove,
-       .suspend        = mxcmci_suspend,
-       .resume         = mxcmci_resume,
        .driver         = {
                .name           = DRIVER_NAME,
                .owner          = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &mxcmci_pm_ops,
+#endif
        }
 };
 
index 82e94389824e74e2c8ca6b8007da09475dc5b1da..0d76b169482f47afff1bbb4f09696c771e3f829e 100644 (file)
@@ -623,8 +623,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
                else
                        host->buf_start = column + mtd->writesize;
 
-               if (mtd->writesize > 512)
-                       command = NAND_CMD_READ0; /* only READ0 is valid */
+               command = NAND_CMD_READ0; /* only READ0 is valid */
 
                send_cmd(host, command, false);
                mxc_do_addr_cycle(mtd, column, page_addr);
@@ -639,31 +638,11 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
                break;
 
        case NAND_CMD_SEQIN:
-               if (column >= mtd->writesize) {
-                       /*
-                        * FIXME: before send SEQIN command for write OOB,
-                        * We must read one page out.
-                        * For K9F1GXX has no READ1 command to set current HW
-                        * pointer to spare area, we must write the whole page
-                        * including OOB together.
-                        */
-                       if (mtd->writesize > 512)
-                               /* call ourself to read a page */
-                               mxc_nand_command(mtd, NAND_CMD_READ0, 0,
-                                               page_addr);
-
-                       host->buf_start = column;
-
-                       /* Set program pointer to spare region */
-                       if (mtd->writesize == 512)
-                               send_cmd(host, NAND_CMD_READOOB, false);
-               } else {
-                       host->buf_start = column;
+               if (column >= mtd->writesize)
+                       /* call ourself to read a page */
+                       mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
 
-                       /* Set program pointer to page start */
-                       if (mtd->writesize == 512)
-                               send_cmd(host, NAND_CMD_READ0, false);
-               }
+               host->buf_start = column;
 
                send_cmd(host, command, false);
                mxc_do_addr_cycle(mtd, column, page_addr);
@@ -853,6 +832,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
            parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
        if (nr_parts > 0)
                add_mtd_partitions(mtd, host->parts, nr_parts);
+       else if (pdata->parts)
+               add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
        else
 #endif
        {
index 13b05cb33b085fbb063a1024f30feb239a82c9de..78ae89488a4fbc54550bf4a7dd54877035b295ec 100644 (file)
@@ -593,6 +593,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
        ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
        ubi->max_ec = si->max_ec;
        ubi->mean_ec = si->mean_ec;
+       ubi_msg("max. sequence number:       %llu", si->max_sqnum);
 
        err = ubi_read_volume_table(ubi, si);
        if (err)
@@ -981,7 +982,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
        ubi_msg("number of PEBs reserved for bad PEB handling: %d",
                ubi->beb_rsvd_pebs);
        ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
-       ubi_msg("image sequence number: %d", ubi->image_seq);
+       ubi_msg("image sequence number:  %d", ubi->image_seq);
 
        /*
         * The below lock makes sure we do not race with 'ubi_thread()' which
index 9f87c99189a99cca2e30dbe35b2a7441203a663e..fe74749e0dae734271b9a6b9e780f11e5cbb021c 100644 (file)
@@ -418,7 +418,8 @@ retry:
                                 * may try to recover data. FIXME: but this is
                                 * not implemented.
                                 */
-                               if (err == UBI_IO_BAD_VID_HDR) {
+                               if (err == UBI_IO_BAD_HDR_READ ||
+                                   err == UBI_IO_BAD_HDR) {
                                        ubi_warn("corrupted VID header at PEB "
                                                 "%d, LEB %d:%d", pnum, vol_id,
                                                 lnum);
@@ -961,8 +962,8 @@ write_error:
  */
 static int is_error_sane(int err)
 {
-       if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR ||
-           err == -ETIMEDOUT)
+       if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR ||
+           err == UBI_IO_BAD_HDR_READ || err == -ETIMEDOUT)
                return 0;
        return 1;
 }
@@ -1164,6 +1165,44 @@ out_unlock_leb:
        return err;
 }
 
+/**
+ * print_rsvd_warning - warn about not having enough reserved PEBs.
+ * @ubi: UBI device description object
+ *
+ * This is a helper function for 'ubi_eba_init_scan()' which is called when UBI
+ * cannot reserve enough PEBs for bad block handling. This function makes a
+ * decision whether we have to print a warning or not. The algorithm is as
+ * follows:
+ *   o if this is a new UBI image, then just print the warning
+ *   o if this is an UBI image which has already been used for some time, print
+ *     a warning only if we can reserve less than 10% of the expected amount of
+ *     the reserved PEB.
+ *
+ * The idea is that when UBI is used, PEBs become bad, and the reserved pool
+ * of PEBs becomes smaller, which is normal and we do not want to scare users
+ * with a warning every time they attach the MTD device. This was an issue
+ * reported by real users.
+ */
+static void print_rsvd_warning(struct ubi_device *ubi,
+                              struct ubi_scan_info *si)
+{
+       /*
+        * The 1 << 18 (256KiB) number is picked randomly, just a reasonably
+        * large number to distinguish between newly flashed and used images.
+        */
+       if (si->max_sqnum > (1 << 18)) {
+               int min = ubi->beb_rsvd_level / 10;
+
+               if (!min)
+                       min = 1;
+               if (ubi->beb_rsvd_pebs > min)
+                       return;
+       }
+
+       ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d,"
+                " need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
+}
+
 /**
  * ubi_eba_init_scan - initialize the EBA sub-system using scanning information.
  * @ubi: UBI device description object
@@ -1236,9 +1275,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                if (ubi->avail_pebs < ubi->beb_rsvd_level) {
                        /* No enough free physical eraseblocks */
                        ubi->beb_rsvd_pebs = ubi->avail_pebs;
-                       ubi_warn("cannot reserve enough PEBs for bad PEB "
-                                "handling, reserved %d, need %d",
-                                ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
+                       print_rsvd_warning(ubi, si);
                } else
                        ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
 
index 4b979e34b159a7f5e7e397404ff89c0cc3421648..332f992f13d982e4d1d46164f673a4f67914ce87 100644 (file)
@@ -150,6 +150,8 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
 retry:
        err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
        if (err) {
+               const char *errstr = (err == -EBADMSG) ? " (ECC error)" : "";
+
                if (err == -EUCLEAN) {
                        /*
                         * -EUCLEAN is reported if there was a bit-flip which
@@ -165,15 +167,15 @@ retry:
                }
 
                if (read != len && retries++ < UBI_IO_RETRIES) {
-                       dbg_io("error %d while reading %d bytes from PEB %d:%d,"
+                       dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
                               " read only %zd bytes, retry",
-                              err, len, pnum, offset, read);
+                              err, errstr, len, pnum, offset, read);
                        yield();
                        goto retry;
                }
 
-               ubi_err("error %d while reading %d bytes from PEB %d:%d, "
-                       "read %zd bytes", err, len, pnum, offset, read);
+               ubi_err("error %d%s while reading %d bytes from PEB %d:%d, "
+                       "read %zd bytes", err, errstr, len, pnum, offset, read);
                ubi_dbg_dump_stack();
 
                /*
@@ -515,7 +517,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
         * In this case we probably anyway have garbage in this PEB.
         */
        err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
-       if (err1 == UBI_IO_BAD_VID_HDR)
+       if (err1 == UBI_IO_BAD_HDR_READ || err1 == UBI_IO_BAD_HDR)
                /*
                 * The VID header is corrupted, so we can safely erase this
                 * PEB and not afraid that it will be treated as a valid PEB in
@@ -709,7 +711,7 @@ bad:
  * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
  *   and corrected by the flash driver; this is harmless but may indicate that
  *   this eraseblock may become bad soon (but may be not);
- * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error);
+ * o %UBI_IO_BAD_HDR if the erase counter header is corrupted (a CRC error);
  * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
  * o a negative error code in case of failure.
  */
@@ -736,23 +738,21 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                 * header is still OK, we just report this as there was a
                 * bit-flip.
                 */
-               read_err = err;
+               if (err == -EBADMSG)
+                       read_err = UBI_IO_BAD_HDR_READ;
        }
 
        magic = be32_to_cpu(ec_hdr->magic);
        if (magic != UBI_EC_HDR_MAGIC) {
+               if (read_err)
+                       return read_err;
+
                /*
                 * The magic field is wrong. Let's check if we have read all
                 * 0xFF. If yes, this physical eraseblock is assumed to be
                 * empty.
-                *
-                * But if there was a read error, we do not test it for all
-                * 0xFFs. Even if it does contain all 0xFFs, this error
-                * indicates that something is still wrong with this physical
-                * eraseblock and we anyway cannot treat it as empty.
                 */
-               if (read_err != -EBADMSG &&
-                   check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
+               if (check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
                        /* The physical eraseblock is supposedly empty */
                        if (verbose)
                                ubi_warn("no EC header found at PEB %d, "
@@ -774,7 +774,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                } else if (UBI_IO_DEBUG)
                        dbg_msg("bad magic number at PEB %d: %08x instead of "
                                "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
-               return UBI_IO_BAD_EC_HDR;
+               return UBI_IO_BAD_HDR;
        }
 
        crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -788,7 +788,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                } else if (UBI_IO_DEBUG)
                        dbg_msg("bad EC header CRC at PEB %d, calculated "
                                "%#08x, read %#08x", pnum, crc, hdr_crc);
-               return UBI_IO_BAD_EC_HDR;
+               return read_err ?: UBI_IO_BAD_HDR;
        }
 
        /* And of course validate what has just been read from the media */
@@ -798,6 +798,10 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                return -EINVAL;
        }
 
+       /*
+        * If there was %-EBADMSG, but the header CRC is still OK, report about
+        * a bit-flip to force scrubbing on this PEB.
+        */
        return read_err ? UBI_IO_BITFLIPS : 0;
 }
 
@@ -977,7 +981,7 @@ bad:
  * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
  *   and corrected by the flash driver; this is harmless but may indicate that
  *   this eraseblock may become bad soon;
- * o %UBI_IO_BAD_VID_HDR if the volume identifier header is corrupted (a CRC
+ * o %UBI_IO_BAD_HDR if the volume identifier header is corrupted (a CRC
  *   error detected);
  * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID
  *   header there);
@@ -1008,22 +1012,20 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                 * CRC check-sum and we will identify this. If the VID header is
                 * still OK, we just report this as there was a bit-flip.
                 */
-               read_err = err;
+               if (err == -EBADMSG)
+                       read_err = UBI_IO_BAD_HDR_READ;
        }
 
        magic = be32_to_cpu(vid_hdr->magic);
        if (magic != UBI_VID_HDR_MAGIC) {
+               if (read_err)
+                       return read_err;
+
                /*
                 * If we have read all 0xFF bytes, the VID header probably does
                 * not exist and the physical eraseblock is assumed to be free.
-                *
-                * But if there was a read error, we do not test the data for
-                * 0xFFs. Even if it does contain all 0xFFs, this error
-                * indicates that something is still wrong with this physical
-                * eraseblock and it cannot be regarded as free.
                 */
-               if (read_err != -EBADMSG &&
-                   check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+               if (check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
                        /* The physical eraseblock is supposedly free */
                        if (verbose)
                                ubi_warn("no VID header found at PEB %d, "
@@ -1045,7 +1047,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                } else if (UBI_IO_DEBUG)
                        dbg_msg("bad magic number at PEB %d: %08x instead of "
                                "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
-               return UBI_IO_BAD_VID_HDR;
+               return UBI_IO_BAD_HDR;
        }
 
        crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
@@ -1059,7 +1061,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                } else if (UBI_IO_DEBUG)
                        dbg_msg("bad CRC at PEB %d, calculated %#08x, "
                                "read %#08x", pnum, crc, hdr_crc);
-               return UBI_IO_BAD_VID_HDR;
+               return read_err ?: UBI_IO_BAD_HDR;
        }
 
        /* Validate the VID header that we have just read */
@@ -1069,6 +1071,10 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                return -EINVAL;
        }
 
+       /*
+        * If there was a read error (%-EBADMSG), but the header CRC is still
+        * OK, report about a bit-flip to force scrubbing on this PEB.
+        */
        return read_err ? UBI_IO_BITFLIPS : 0;
 }
 
index aed19f33b8f3ec1685fd40acf121df738c2c77d4..372a15ac9995a64c7fc8f8084c75cb59ba4251d1 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/crc32.h>
 #include <linux/math64.h>
+#include <linux/random.h>
 #include "ubi.h"
 
 #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
@@ -72,16 +73,19 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
 {
        struct ubi_scan_leb *seb;
 
-       if (list == &si->free)
+       if (list == &si->free) {
                dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
-       else if (list == &si->erase)
+               si->free_peb_count += 1;
+       } else if (list == &si->erase) {
                dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
-       else if (list == &si->corr) {
+               si->erase_peb_count += 1;
+       } else if (list == &si->corr) {
                dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
-               si->corr_count += 1;
-       } else if (list == &si->alien)
+               si->corr_peb_count += 1;
+       } else if (list == &si->alien) {
                dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
-       else
+               si->alien_peb_count += 1;
+       } else
                BUG();
 
        seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
@@ -517,6 +521,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
        sv->leb_count += 1;
        rb_link_node(&seb->u.rb, parent, p);
        rb_insert_color(&seb->u.rb, &sv->root);
+       si->used_peb_count += 1;
        return 0;
 }
 
@@ -745,19 +750,17 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
                bitflips = 1;
        else if (err == UBI_IO_PEB_EMPTY)
                return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
-       else if (err == UBI_IO_BAD_EC_HDR) {
+       else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR) {
                /*
                 * We have to also look at the VID header, possibly it is not
                 * corrupted. Set %bitflips flag in order to make this PEB be
                 * moved and EC be re-created.
                 */
-               ec_corr = 1;
+               ec_corr = err;
                ec = UBI_SCAN_UNKNOWN_EC;
                bitflips = 1;
        }
 
-       si->is_empty = 0;
-
        if (!ec_corr) {
                int image_seq;
 
@@ -813,9 +816,12 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
                return err;
        else if (err == UBI_IO_BITFLIPS)
                bitflips = 1;
-       else if (err == UBI_IO_BAD_VID_HDR ||
+       else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR ||
                 (err == UBI_IO_PEB_FREE && ec_corr)) {
                /* VID header is corrupted */
+               if (err == UBI_IO_BAD_HDR_READ ||
+                   ec_corr == UBI_IO_BAD_HDR_READ)
+                       si->read_err_count += 1;
                err = add_to_list(si, pnum, ec, &si->corr);
                if (err)
                        return err;
@@ -836,11 +842,11 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
                switch (vidh->compat) {
                case UBI_COMPAT_DELETE:
                        ubi_msg("\"delete\" compatible internal volume %d:%d"
-                               " found, remove it", vol_id, lnum);
+                               " found, will remove it", vol_id, lnum);
                        err = add_to_list(si, pnum, ec, &si->corr);
                        if (err)
                                return err;
-                       break;
+                       return 0;
 
                case UBI_COMPAT_RO:
                        ubi_msg("read-only compatible internal volume %d:%d"
@@ -855,7 +861,6 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
                        err = add_to_list(si, pnum, ec, &si->alien);
                        if (err)
                                return err;
-                       si->alien_peb_count += 1;
                        return 0;
 
                case UBI_COMPAT_REJECT:
@@ -885,6 +890,85 @@ adjust_mean_ec:
        return 0;
 }
 
+/**
+ * check_what_we_have - check what PEB were found by scanning.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This is a helper function which takes a look what PEBs were found by
+ * scanning, and decides whether the flash is empty and should be formatted and
+ * whether there are too many corrupted PEBs and we should not attach this
+ * MTD device. Returns zero if we should proceed with attaching the MTD device,
+ * and %-EINVAL if we should not.
+ */
+static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+       struct ubi_scan_leb *seb;
+       int max_corr;
+
+       max_corr = ubi->peb_count - si->bad_peb_count - si->alien_peb_count;
+       max_corr = max_corr / 20 ?: 8;
+
+       /*
+        * Few corrupted PEBs are not a problem and may be just a result of
+        * unclean reboots. However, many of them may indicate some problems
+        * with the flash HW or driver.
+        */
+       if (si->corr_peb_count >= 8) {
+               ubi_warn("%d PEBs are corrupted", si->corr_peb_count);
+               printk(KERN_WARNING "corrupted PEBs are:");
+               list_for_each_entry(seb, &si->corr, u.list)
+                       printk(KERN_CONT " %d", seb->pnum);
+               printk(KERN_CONT "\n");
+
+               /*
+                * If too many PEBs are corrupted, we refuse attaching,
+                * otherwise, only print a warning.
+                */
+               if (si->corr_peb_count >= max_corr) {
+                       ubi_err("too many corrupted PEBs, refusing this device");
+                       return -EINVAL;
+               }
+       }
+
+       if (si->free_peb_count + si->used_peb_count +
+           si->alien_peb_count == 0) {
+               /* No UBI-formatted eraseblocks were found */
+               if (si->corr_peb_count == si->read_err_count &&
+                   si->corr_peb_count < 8) {
+                       /* No or just few corrupted PEBs, and all of them had a
+                        * read error. We assume that those are bad PEBs, which
+                        * were just not marked as bad so far.
+                        *
+                        * This piece of code basically tries to distinguish
+                        * between the following 2 situations:
+                        *
+                        * 1. Flash is empty, but there are few bad PEBs, which
+                        *    are not marked as bad so far, and which were read
+                        *    with error. We want to go ahead and format this
+                        *    flash. While formating, the faulty PEBs will
+                        *    probably be marked as bad.
+                        *
+                        * 2. Flash probably contains non-UBI data and we do
+                        * not want to format it and destroy possibly needed
+                        * data (e.g., consider the case when the bootloader
+                        * MTD partition was accidentally fed to UBI).
+                        */
+                       si->is_empty = 1;
+                       ubi_msg("empty MTD device detected");
+                       get_random_bytes(&ubi->image_seq, sizeof(ubi->image_seq));
+               } else {
+                       ubi_err("MTD device possibly contains non-UBI data, "
+                               "refusing it");
+                       return -EINVAL;
+               }
+       }
+
+       if (si->corr_peb_count > 0)
+               ubi_msg("corrupted PEBs will be formatted");
+       return 0;
+}
+
 /**
  * ubi_scan - scan an MTD device.
  * @ubi: UBI device description object
@@ -909,7 +993,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
        INIT_LIST_HEAD(&si->erase);
        INIT_LIST_HEAD(&si->alien);
        si->volumes = RB_ROOT;
-       si->is_empty = 1;
 
        err = -ENOMEM;
        ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
@@ -935,21 +1018,9 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
        if (si->ec_count)
                si->mean_ec = div_u64(si->ec_sum, si->ec_count);
 
-       if (si->is_empty)
-               ubi_msg("empty MTD device detected");
-
-       /*
-        * Few corrupted PEBs are not a problem and may be just a result of
-        * unclean reboots. However, many of them may indicate some problems
-        * with the flash HW or driver. Print a warning in this case.
-        */
-       if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
-               ubi_warn("%d PEBs are corrupted", si->corr_count);
-               printk(KERN_WARNING "corrupted PEBs are:");
-               list_for_each_entry(seb, &si->corr, u.list)
-                       printk(KERN_CONT " %d", seb->pnum);
-               printk(KERN_CONT "\n");
-       }
+       err = check_what_we_have(ubi, si);
+       if (err)
+               goto out_vidh;
 
        /*
         * In case of unknown erase counter we use the mean erase counter
index ff179ad7ca55965ed4a710c1910721e47f6c36e6..2576a8d1532b700d659391bbe6d3e1364acbcaef 100644 (file)
@@ -91,10 +91,16 @@ struct ubi_scan_volume {
  * @erase: list of physical eraseblocks which have to be erased
  * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
  *         those belonging to "preserve"-compatible internal volumes)
+ * @used_peb_count: count of used PEBs
+ * @corr_peb_count: count of PEBs in the @corr list
+ * @read_err_count: count of PEBs read with error (%UBI_IO_BAD_HDR_READ was
+ *                  returned)
+ * @free_peb_count: count of PEBs in the @free list
+ * @erase_peb_count: count of PEBs in the @erase list
+ * @alien_peb_count: count of PEBs in the @alien list
  * @bad_peb_count: count of bad physical eraseblocks
  * @vols_found: number of volumes found during scanning
  * @highest_vol_id: highest volume ID
- * @alien_peb_count: count of physical eraseblocks in the @alien list
  * @is_empty: flag indicating whether the MTD device is empty or not
  * @min_ec: lowest erase counter value
  * @max_ec: highest erase counter value
@@ -102,7 +108,6 @@ struct ubi_scan_volume {
  * @mean_ec: mean erase counter value
  * @ec_sum: a temporary variable used when calculating @mean_ec
  * @ec_count: a temporary variable used when calculating @mean_ec
- * @corr_count: count of corrupted PEBs
  *
  * This data structure contains the result of scanning and may be used by other
  * UBI sub-systems to build final UBI data structures, further error-recovery
@@ -114,10 +119,15 @@ struct ubi_scan_info {
        struct list_head free;
        struct list_head erase;
        struct list_head alien;
+       int used_peb_count;
+       int corr_peb_count;
+       int read_err_count;
+       int free_peb_count;
+       int erase_peb_count;
+       int alien_peb_count;
        int bad_peb_count;
        int vols_found;
        int highest_vol_id;
-       int alien_peb_count;
        int is_empty;
        int min_ec;
        int max_ec;
@@ -125,7 +135,6 @@ struct ubi_scan_info {
        int mean_ec;
        uint64_t ec_sum;
        int ec_count;
-       int corr_count;
 };
 
 struct ubi_device;
@@ -135,7 +144,7 @@ struct ubi_vid_hdr;
  * ubi_scan_move_to_list - move a PEB from the volume tree to a list.
  *
  * @sv: volume scanning information
- * @seb: scanning eraseblock infprmation
+ * @seb: scanning eraseblock information
  * @list: the list to move to
  */
 static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
index a637f0283add2fd98d006228b18a3bff3c8b79be..0359e0cce4827ea7dd778d188b5ff7d6dde5b9d3 100644 (file)
  *                   %0xFF bytes
  * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a
  *                  valid erase counter header, and the rest are %0xFF bytes
- * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
- * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or
- *                     CRC)
+ * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC)
+ * UBI_IO_BAD_HDR_READ: the same as %UBI_IO_BAD_HDR, but also there was a read
+ *                     error reported by the flash driver
  * UBI_IO_BITFLIPS: bit-flips were detected and corrected
  */
 enum {
        UBI_IO_PEB_EMPTY = 1,
        UBI_IO_PEB_FREE,
-       UBI_IO_BAD_EC_HDR,
-       UBI_IO_BAD_VID_HDR,
+       UBI_IO_BAD_HDR,
+       UBI_IO_BAD_HDR_READ,
        UBI_IO_BITFLIPS
 };
 
index 78b74e83ce5df7f242fe579676f7623c8d84e6f3..5a1bd5db2a93b3bfc3540e5cd81b76d05b553e0e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/phy.h>
+#include <linux/marvell_phy.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -48,8 +49,6 @@
 #define MII_M1145_RGMII_RX_DELAY       0x0080
 #define MII_M1145_RGMII_TX_DELAY       0x0002
 
-#define M1145_DEV_FLAGS_RESISTANCE     0x00000001
-
 #define MII_M1111_PHY_LED_CONTROL      0x18
 #define MII_M1111_PHY_LED_DIRECT       0x4100
 #define MII_M1111_PHY_LED_COMBINE      0x411c
@@ -350,7 +349,10 @@ static int m88e1118_config_init(struct phy_device *phydev)
                return err;
 
        /* Adjust LED Control */
-       err = phy_write(phydev, 0x10, 0x021e);
+       if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
+               err = phy_write(phydev, 0x10, 0x1100);
+       else
+               err = phy_write(phydev, 0x10, 0x021e);
        if (err < 0)
                return err;
 
@@ -398,7 +400,7 @@ static int m88e1145_config_init(struct phy_device *phydev)
                if (err < 0)
                        return err;
 
-               if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
+               if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
                        err = phy_write(phydev, 0x1d, 0x0012);
                        if (err < 0)
                                return err;
@@ -529,8 +531,8 @@ static int m88e1121_did_interrupt(struct phy_device *phydev)
 
 static struct phy_driver marvell_drivers[] = {
        {
-               .phy_id = 0x01410c60,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1101,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1101",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
@@ -541,8 +543,8 @@ static struct phy_driver marvell_drivers[] = {
                .driver = { .owner = THIS_MODULE },
        },
        {
-               .phy_id = 0x01410c90,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1112,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1112",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
@@ -554,8 +556,8 @@ static struct phy_driver marvell_drivers[] = {
                .driver = { .owner = THIS_MODULE },
        },
        {
-               .phy_id = 0x01410cc0,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1111,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1111",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
@@ -567,8 +569,8 @@ static struct phy_driver marvell_drivers[] = {
                .driver = { .owner = THIS_MODULE },
        },
        {
-               .phy_id = 0x01410e10,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1118,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1118",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
@@ -580,8 +582,8 @@ static struct phy_driver marvell_drivers[] = {
                .driver = {.owner = THIS_MODULE,},
        },
        {
-               .phy_id = 0x01410cb0,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1121R,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1121R",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
@@ -593,8 +595,8 @@ static struct phy_driver marvell_drivers[] = {
                .driver = { .owner = THIS_MODULE },
        },
        {
-               .phy_id = 0x01410cd0,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1145,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1145",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
@@ -606,8 +608,8 @@ static struct phy_driver marvell_drivers[] = {
                .driver = { .owner = THIS_MODULE },
        },
        {
-               .phy_id = 0x01410e30,
-               .phy_id_mask = 0xfffffff0,
+               .phy_id = MARVELL_PHY_ID_88E1240,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
                .name = "Marvell 88E1240",
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
index 188bc8496a264feb05758e36cd7c2e23dea37b63..d02be78a41386b2ecb94c249cff8da11776ecb4a 100644 (file)
@@ -176,16 +176,18 @@ static ssize_t led_proc_write(struct file *file, const char *buf,
        size_t count, loff_t *pos)
 {
        void *data = PDE(file->f_path.dentry->d_inode)->data;
-       char *cur, lbuf[count + 1];
+       char *cur, lbuf[32];
        int d;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       memset(lbuf, 0, count + 1);
+       if (count >= sizeof(lbuf))
+               count = sizeof(lbuf)-1;
 
        if (copy_from_user(lbuf, buf, count))
                return -EFAULT;
+       lbuf[count] = 0;
 
        cur = lbuf;
 
index 3587d9922f2895832059f1ea1163e715750dd19a..71bbefc3544ee7782539083ace3ca2ea11931a1e 100644 (file)
@@ -456,7 +456,7 @@ static struct rtc_class_ops stv2_pl031_ops = {
        .irq_set_freq = pl031_irq_set_freq,
 };
 
-static struct amba_id pl031_ids[] __initdata = {
+static struct amba_id pl031_ids[] = {
        {
                .id = 0x00041031,
                .mask = 0x000fffff,
index b09a638d051fde98c37e52a58eb2cb9a25756663..50441ffe8e3856592dbfdae368e9891b64078d50 100644 (file)
@@ -782,7 +782,7 @@ static int pl010_resume(struct amba_device *dev)
        return 0;
 }
 
-static struct amba_id pl010_ids[] __initdata = {
+static struct amba_id pl010_ids[] = {
        {
                .id     = 0x00041010,
                .mask   = 0x000fffff,
index eb4cb480b93e9be344f9f84bbd574c68fe3ec8e6..6ca7a44f29c205ef37c95318253e2592efaa459b 100644 (file)
 struct uart_amba_port {
        struct uart_port        port;
        struct clk              *clk;
-       unsigned int            im;     /* interrupt mask */
+       unsigned int            im;             /* interrupt mask */
        unsigned int            old_status;
-       unsigned int            ifls;   /* vendor-specific */
+       unsigned int            ifls;           /* vendor-specific */
+       unsigned int            lcrh_tx;        /* vendor-specific */
+       unsigned int            lcrh_rx;        /* vendor-specific */
+       bool                    oversampling;   /* vendor-specific */
        bool                    autorts;
 };
 
@@ -79,16 +82,25 @@ struct uart_amba_port {
 struct vendor_data {
        unsigned int            ifls;
        unsigned int            fifosize;
+       unsigned int            lcrh_tx;
+       unsigned int            lcrh_rx;
+       bool                    oversampling;
 };
 
 static struct vendor_data vendor_arm = {
        .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
        .fifosize               = 16,
+       .lcrh_tx                = UART011_LCRH,
+       .lcrh_rx                = UART011_LCRH,
+       .oversampling           = false,
 };
 
 static struct vendor_data vendor_st = {
        .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
        .fifosize               = 64,
+       .lcrh_tx                = ST_UART011_LCRH_TX,
+       .lcrh_rx                = ST_UART011_LCRH_RX,
+       .oversampling           = true,
 };
 
 static void pl011_stop_tx(struct uart_port *port)
@@ -327,12 +339,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
        unsigned int lcr_h;
 
        spin_lock_irqsave(&uap->port.lock, flags);
-       lcr_h = readw(uap->port.membase + UART011_LCRH);
+       lcr_h = readw(uap->port.membase + uap->lcrh_tx);
        if (break_state == -1)
                lcr_h |= UART01x_LCRH_BRK;
        else
                lcr_h &= ~UART01x_LCRH_BRK;
-       writew(lcr_h, uap->port.membase + UART011_LCRH);
+       writew(lcr_h, uap->port.membase + uap->lcrh_tx);
        spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
@@ -393,7 +405,17 @@ static int pl011_startup(struct uart_port *port)
        writew(cr, uap->port.membase + UART011_CR);
        writew(0, uap->port.membase + UART011_FBRD);
        writew(1, uap->port.membase + UART011_IBRD);
-       writew(0, uap->port.membase + UART011_LCRH);
+       writew(0, uap->port.membase + uap->lcrh_rx);
+       if (uap->lcrh_tx != uap->lcrh_rx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(0, uap->port.membase + uap->lcrh_tx);
+       }
        writew(0, uap->port.membase + UART01x_DR);
        while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
                barrier();
@@ -422,10 +444,19 @@ static int pl011_startup(struct uart_port *port)
        return retval;
 }
 
+static void pl011_shutdown_channel(struct uart_amba_port *uap,
+                                       unsigned int lcrh)
+{
+      unsigned long val;
+
+      val = readw(uap->port.membase + lcrh);
+      val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
+      writew(val, uap->port.membase + lcrh);
+}
+
 static void pl011_shutdown(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned long val;
 
        /*
         * disable all interrupts
@@ -450,9 +481,9 @@ static void pl011_shutdown(struct uart_port *port)
        /*
         * disable break condition and fifos
         */
-       val = readw(uap->port.membase + UART011_LCRH);
-       val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
-       writew(val, uap->port.membase + UART011_LCRH);
+       pl011_shutdown_channel(uap, uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx)
+               pl011_shutdown_channel(uap, uap->lcrh_tx);
 
        /*
         * Shut down the clock producer
@@ -472,8 +503,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
        /*
         * Ask the core to calculate the divisor for us.
         */
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = port->uartclk * 4 / baud;
+       baud = uart_get_baud_rate(port, termios, old, 0,
+                                 port->uartclk/(uap->oversampling ? 8 : 16));
+
+       if (baud > port->uartclk/16)
+               quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
+       else
+               quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
@@ -552,6 +588,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
                uap->autorts = false;
        }
 
+       if (uap->oversampling) {
+               if (baud > port->uartclk/16)
+                       old_cr |= ST_UART011_CR_OVSFACT;
+               else
+                       old_cr &= ~ST_UART011_CR_OVSFACT;
+       }
+
        /* Set baud rate */
        writew(quot & 0x3f, port->membase + UART011_FBRD);
        writew(quot >> 6, port->membase + UART011_IBRD);
@@ -561,7 +604,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
         * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
         * ----------^----------^----------^----------^-----
         */
-       writew(lcr_h, port->membase + UART011_LCRH);
+       writew(lcr_h, port->membase + uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(lcr_h, port->membase + uap->lcrh_tx);
+       }
        writew(old_cr, port->membase + UART011_CR);
 
        spin_unlock_irqrestore(&port->lock, flags);
@@ -688,7 +741,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
        if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
                unsigned int lcr_h, ibrd, fbrd;
 
-               lcr_h = readw(uap->port.membase + UART011_LCRH);
+               lcr_h = readw(uap->port.membase + uap->lcrh_tx);
 
                *parity = 'n';
                if (lcr_h & UART01x_LCRH_PEN) {
@@ -707,6 +760,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
                fbrd = readw(uap->port.membase + UART011_FBRD);
 
                *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
+
+               if (uap->oversampling) {
+                       if (readw(uap->port.membase + UART011_CR)
+                                 & ST_UART011_CR_OVSFACT)
+                               *baud *= 2;
+               }
        }
 }
 
@@ -800,6 +859,9 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
        }
 
        uap->ifls = vendor->ifls;
+       uap->lcrh_rx = vendor->lcrh_rx;
+       uap->lcrh_tx = vendor->lcrh_tx;
+       uap->oversampling = vendor->oversampling;
        uap->port.dev = &dev->dev;
        uap->port.mapbase = dev->res.start;
        uap->port.membase = base;
@@ -868,7 +930,7 @@ static int pl011_resume(struct amba_device *dev)
 }
 #endif
 
-static struct amba_id pl011_ids[] __initdata = {
+static struct amba_id pl011_ids[] = {
        {
                .id     = 0x00041011,
                .mask   = 0x000fffff,
index 984a75440710673efe2c50ea5967c460a7ef3d12..9296517258553dece8f2dae6dc5829c116933b93 100644 (file)
@@ -147,5 +147,7 @@ source "drivers/staging/mrst-touchscreen/Kconfig"
 
 source "drivers/staging/msm/Kconfig"
 
+source "drivers/staging/lirc/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index 9fa25133874afc9b0c2a4c4b31a87f0aa98468d3..6c5b5237ccb9fdf472cc8bbc28868edef7864a83 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_SLICOSS)           += slicoss/
 obj-$(CONFIG_VIDEO_GO7007)     += go7007/
 obj-$(CONFIG_VIDEO_CX25821)    += cx25821/
 obj-$(CONFIG_VIDEO_TM6000)     += tm6000/
+obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_USB_IP_COMMON)    += usbip/
 obj-$(CONFIG_W35UND)           += winbond/
 obj-$(CONFIG_PRISM2_USB)       += wlan-ng/
index 10f87f05d8e8e31ecda97d57c14aee4317bcd87b..d0eb16eac092ae75bc86684255e7048ab3b8269d 100644 (file)
@@ -1,9 +1,8 @@
-cx25821-objs   := cx25821-core.o cx25821-cards.o cx25821-i2c.o cx25821-gpio.o                          \
-                               cx25821-medusa-video.o cx25821-video.o cx25821-video0.o cx25821-video1.o    \
-                               cx25821-video2.o cx25821-video3.o cx25821-video4.o cx25821-video5.o         \
-                               cx25821-video6.o cx25821-video7.o cx25821-vidups9.o cx25821-vidups10.o      \
-                               cx25821-audups11.o cx25821-video-upstream.o cx25821-video-upstream-ch2.o        \
-                               cx25821-audio-upstream.o cx25821-videoioctl.o
+cx25821-objs   := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
+                      cx25821-gpio.o cx25821-medusa-video.o \
+                      cx25821-video.o cx25821-video-upstream.o \
+                      cx25821-video-upstream-ch2.o \
+                      cx25821-audio-upstream.o
 
 obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
 obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
index 1798975a69bdf814a33356781f6c759e8c4336e7..a43b18816fa51b372f76704cec75c9e185fc6c50 100644 (file)
 static struct snd_card *snd_cx25821_cards[SNDRV_CARDS];
 static int devno;
 
+struct cx25821_audio_buffer {
+       unsigned int bpl;
+       struct btcx_riscmem risc;
+       struct videobuf_dmabuf dma;
+};
+
 struct cx25821_audio_dev {
        struct cx25821_dev *dev;
        struct cx25821_dmaqueue q;
@@ -77,7 +83,7 @@ struct cx25821_audio_dev {
 
        struct videobuf_dmabuf *dma_risc;
 
-       struct cx25821_buffer *buf;
+       struct cx25821_audio_buffer *buf;
 
        struct snd_pcm_substream *substream;
 };
@@ -136,7 +142,7 @@ MODULE_PARM_DESC(debug, "enable debug messages");
 
 static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
 {
-       struct cx25821_buffer *buf = chip->buf;
+       struct cx25821_audio_buffer *buf = chip->buf;
        struct cx25821_dev *dev = chip->dev;
        struct sram_channel *audio_ch =
            &cx25821_sram_channels[AUDIO_SRAM_CHANNEL];
@@ -331,7 +337,7 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip)
        BUG_ON(!chip->dma_size);
 
        dprintk(2, "Freeing buffer\n");
-       videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+       videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
        videobuf_dma_free(chip->dma_risc);
        btcx_riscmem_free(chip->pci, &chip->buf->risc);
        kfree(chip->buf);
@@ -432,7 +438,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
        struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
        struct videobuf_dmabuf *dma;
 
-       struct cx25821_buffer *buf;
+       struct cx25821_audio_buffer *buf;
        int ret;
 
        if (substream->runtime->dma_area) {
@@ -447,36 +453,31 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
        BUG_ON(!chip->dma_size);
        BUG_ON(chip->num_periods & (chip->num_periods - 1));
 
-       buf = videobuf_sg_alloc(sizeof(*buf));
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
        if (NULL == buf)
                return -ENOMEM;
 
        if (chip->period_size > AUDIO_LINE_SIZE)
                chip->period_size = AUDIO_LINE_SIZE;
 
-       buf->vb.memory = V4L2_MEMORY_MMAP;
-       buf->vb.field = V4L2_FIELD_NONE;
-       buf->vb.width = chip->period_size;
        buf->bpl = chip->period_size;
-       buf->vb.height = chip->num_periods;
-       buf->vb.size = chip->dma_size;
 
-       dma = videobuf_to_dma(&buf->vb);
+       dma = &buf->dma;
        videobuf_dma_init(dma);
-
        ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
-                                      (PAGE_ALIGN(buf->vb.size) >>
+                                      (PAGE_ALIGN(chip->dma_size) >>
                                        PAGE_SHIFT));
        if (ret < 0)
                goto error;
 
-       ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+       ret = videobuf_dma_map(&chip->pci->dev, dma);
        if (ret < 0)
                goto error;
 
        ret =
            cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
-                                         buf->vb.width, buf->vb.height, 1);
+                                         chip->period_size, chip->num_periods,
+                                         1);
        if (ret < 0) {
                printk(KERN_INFO
                        "DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
@@ -488,12 +489,10 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
        buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
        buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
 
-       buf->vb.state = VIDEOBUF_PREPARED;
-
        chip->buf = buf;
        chip->dma_risc = dma;
 
-       substream->runtime->dma_area = chip->dma_risc->vmalloc;
+       substream->runtime->dma_area = chip->dma_risc->vaddr;
        substream->runtime->dma_bytes = chip->dma_size;
        substream->runtime->dma_addr = 0;
 
index eb39d13f7d75afe40a20610f9ae152770a71137b..cdff49f409f25f4161ee30fea5bd535eaddb2a71 100644 (file)
@@ -106,7 +106,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
 {
        unsigned int line;
        struct sram_channel *sram_ch =
-           &dev->sram_channels[dev->_audio_upstream_channel_select];
+          dev->channels[dev->_audio_upstream_channel_select].sram_channels;
        int offset = 0;
 
        /* scan lines */
@@ -217,7 +217,7 @@ void cx25821_free_memory_audio(struct cx25821_dev *dev)
 void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
 {
        struct sram_channel *sram_ch =
-           &dev->sram_channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B];
+          dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
        u32 tmp = 0;
 
        if (!dev->_audio_is_running) {
@@ -287,14 +287,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
-                       printk("%s: File has no file operations registered!\n",
+                       printk(KERN_ERR "%s: File has no file operations registered!\n",
                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
 
                if (!myfile->f_op->read) {
-                       printk("%s: File has no READ operations registered!\n",
+                       printk(KERN_ERR "%s: File has no READ operations registered!\n",
                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
@@ -353,8 +353,9 @@ static void cx25821_audioups_handler(struct work_struct *work)
        }
 
        cx25821_get_audio_data(dev,
-                              &dev->sram_channels[dev->
-                                                  _audio_upstream_channel_select]);
+                             dev->channels[dev->
+                                      _audio_upstream_channel_select].
+                                      sram_channels);
 }
 
 int cx25821_openfile_audio(struct cx25821_dev *dev,
@@ -378,14 +379,14 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
-                       printk("%s: File has no file operations registered!\n",
+                       printk(KERN_ERR "%s: File has no file operations registered!\n",
                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
 
                if (!myfile->f_op->read) {
-                       printk("%s: File has no READ operations registered!\n",
+                       printk(KERN_ERR "%s: File has no READ operations registered!\n",
                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
@@ -505,7 +506,7 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
 {
        int i = 0;
        u32 int_msk_tmp;
-       struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
        dma_addr_t risc_phys_jump_addr;
        __le32 *rp;
 
@@ -569,15 +570,15 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
                spin_unlock(&dev->slock);
        } else {
                if (status & FLD_AUD_SRC_OF)
-                       printk("%s: Audio Received Overflow Error Interrupt!\n",
+                       printk(KERN_WARNING "%s: Audio Received Overflow Error Interrupt!\n",
                               __func__);
 
                if (status & FLD_AUD_SRC_SYNC)
-                       printk("%s: Audio Received Sync Error Interrupt!\n",
+                       printk(KERN_WARNING "%s: Audio Received Sync Error Interrupt!\n",
                               __func__);
 
                if (status & FLD_AUD_SRC_OPC_ERR)
-                       printk("%s: Audio Received OpCode Error Interrupt!\n",
+                       printk(KERN_WARNING "%s: Audio Received OpCode Error Interrupt!\n",
                               __func__);
 
                /* Read and write back the interrupt status register to clear
@@ -586,7 +587,7 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
        }
 
        if (dev->_audiofile_status == END_OF_FILE) {
-               printk("cx25821: EOF Channel Audio Framecount = %d\n",
+               printk(KERN_WARNING "cx25821: EOF Channel Audio Framecount = %d\n",
                       dev->_audioframe_count);
                return -1;
        }
@@ -607,7 +608,8 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
        if (!dev)
                return -1;
 
-       sram_ch = &dev->sram_channels[dev->_audio_upstream_channel_select];
+       sram_ch = dev->channels[dev->_audio_upstream_channel_select].
+                                      sram_channels;
 
        msk_stat = cx_read(sram_ch->int_mstat);
        audio_status = cx_read(sram_ch->int_stat);
@@ -644,8 +646,8 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
 
                /* 10 millisecond timeout */
                if (count++ > 1000) {
-                       printk
-                           ("cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
+                       printk(KERN_ERR
+                              "cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
                             __func__);
                        return;
                }
@@ -726,12 +728,12 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
        int str_length = 0;
 
        if (dev->_audio_is_running) {
-               printk("Audio Channel is still running so return!\n");
+               printk(KERN_WARNING "Audio Channel is still running so return!\n");
                return 0;
        }
 
        dev->_audio_upstream_channel_select = channel_select;
-       sram_ch = &dev->sram_channels[channel_select];
+       sram_ch = dev->channels[channel_select].sram_channels;
 
        /* Work queue */
        INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler);
index 503f42f036a89c7657845bed1ad63e6f32c6a74f..434b2a312a80e29eb17ca164e023b020a04747d6 100644 (file)
 #define LINES_PER_BUFFER            15
 #define AUDIO_LINE_SIZE             128
 
-//Number of buffer programs to use at once.
+/* Number of buffer programs to use at once. */
 #define NUMBER_OF_PROGRAMS  8
 
-//Max size of the RISC program for a buffer. - worst case is 2 writes per line
-// Space is also added for the 4 no-op instructions added on the end.
-
+/*
+  Max size of the RISC program for a buffer. - worst case is 2 writes per line
+  Space is also added for the 4 no-op instructions added on the end.
+*/
 #ifndef USE_RISC_NOOP
 #define MAX_BUFFER_PROGRAM_SIZE     \
     (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE*4)
 #endif
 
-// MAE 12 July 2005 Try to use NOOP RISC instruction instead
+/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
 #ifdef USE_RISC_NOOP
 #define MAX_BUFFER_PROGRAM_SIZE     \
     (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4)
 #endif
 
-//Sizes of various instructions in bytes.  Used when adding instructions.
+/* Sizes of various instructions in bytes.  Used when adding instructions. */
 #define RISC_WRITE_INSTRUCTION_SIZE 12
 #define RISC_JUMP_INSTRUCTION_SIZE  12
 #define RISC_SKIP_INSTRUCTION_SIZE  4
diff --git a/drivers/staging/cx25821/cx25821-audups11.c b/drivers/staging/cx25821/cx25821-audups11.c
deleted file mode 100644 (file)
index e49ead9..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include <linux/slab.h>
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH11];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH11]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = 10;
-       fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO11))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       //cx_write(channel11->dma_ctl, 0);
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO11);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO11)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO11);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width = f->fmt.pix.width;
-       fh->height = f->fmt.pix.height;
-       fh->vidq.field = f->fmt.pix.field;
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-       return 0;
-}
-
-static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
-                                  unsigned long arg)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-       int command = 0;
-       struct upstream_user_struct *data_from_user;
-
-       data_from_user = (struct upstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               printk
-                   ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
-                    __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO) {
-               return 0;
-       }
-
-       dev->input_filename = data_from_user->input_filename;
-       dev->input_audiofilename = data_from_user->input_filename;
-       dev->vid_stdname = data_from_user->vid_stdname;
-       dev->pixel_format = data_from_user->pixel_format;
-       dev->channel_select = data_from_user->channel_select;
-       dev->command = data_from_user->command;
-
-       switch (command) {
-       case UPSTREAM_START_AUDIO:
-               cx25821_start_upstream_audio(dev, data_from_user);
-               break;
-
-       case UPSTREAM_STOP_AUDIO:
-               cx25821_stop_upstream_audio(dev);
-               break;
-       }
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct cx25821_fh *fh = priv;
-       return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev;
-       int err;
-
-       if (fh) {
-               dev = fh->dev;
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-       return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl_upstream11,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template11 = {
-       .name = "cx25821-audioupstream",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
index d90abb383fc83c2cbe5ae9709ee886c447f29b4c..c487c19256b94af7710db77d41ff9f5d850fa9f2 100644 (file)
@@ -781,14 +781,14 @@ static void cx25821_shutdown(struct cx25821_dev *dev)
 
        /* Disable Video A/B activity */
        for (i = 0; i < VID_CHANNEL_NUM; i++) {
-               cx_write(dev->sram_channels[i].dma_ctl, 0);
-               cx_write(dev->sram_channels[i].int_msk, 0);
+              cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+              cx_write(dev->channels[i].sram_channels->int_msk, 0);
        }
 
        for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
             i++) {
-               cx_write(dev->sram_channels[i].dma_ctl, 0);
-               cx_write(dev->sram_channels[i].int_msk, 0);
+              cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+              cx_write(dev->channels[i].sram_channels->int_msk, 0);
        }
 
        /* Disable Audio activity */
@@ -805,12 +805,10 @@ static void cx25821_shutdown(struct cx25821_dev *dev)
 void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
                              u32 format)
 {
-       struct sram_channel *ch;
-
        if (channel_select <= 7 && channel_select >= 0) {
-               ch = &cx25821_sram_channels[channel_select];
-               cx_write(ch->pix_frmt, format);
-               dev->pixel_formats[channel_select] = format;
+              cx_write(dev->channels[channel_select].
+                              sram_channels->pix_frmt, format);
+              dev->channels[channel_select].pixel_formats = format;
        }
 }
 
@@ -831,7 +829,7 @@ static void cx25821_initialize(struct cx25821_dev *dev)
        cx_write(PCI_INT_STAT, 0xffffffff);
 
        for (i = 0; i < VID_CHANNEL_NUM; i++)
-               cx_write(dev->sram_channels[i].int_stat, 0xffffffff);
+              cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
 
        cx_write(AUD_A_INT_STAT, 0xffffffff);
        cx_write(AUD_B_INT_STAT, 0xffffffff);
@@ -845,21 +843,22 @@ static void cx25821_initialize(struct cx25821_dev *dev)
        mdelay(100);
 
        for (i = 0; i < VID_CHANNEL_NUM; i++) {
-               cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
-               cx25821_sram_channel_setup(dev, &dev->sram_channels[i], 1440,
-                                          0);
-               dev->pixel_formats[i] = PIXEL_FRMT_422;
-               dev->use_cif_resolution[i] = FALSE;
+              cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+              cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
+                                              1440, 0);
+              dev->channels[i].pixel_formats = PIXEL_FRMT_422;
+              dev->channels[i].use_cif_resolution = FALSE;
        }
 
        /* Probably only affect Downstream */
        for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
             i++) {
-               cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
+              cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
        }
 
-       cx25821_sram_channel_setup_audio(dev, &dev->sram_channels[SRAM_CH08],
-                                        128, 0);
+       cx25821_sram_channel_setup_audio(dev,
+                              dev->channels[SRAM_CH08].sram_channels,
+                              128, 0);
 
        cx25821_gpio_init(dev);
 }
@@ -902,21 +901,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
 {
        int io_size = 0, i;
 
-       struct video_device *video_template[] = {
-               &cx25821_video_template0,
-               &cx25821_video_template1,
-               &cx25821_video_template2,
-               &cx25821_video_template3,
-               &cx25821_video_template4,
-               &cx25821_video_template5,
-               &cx25821_video_template6,
-               &cx25821_video_template7,
-               &cx25821_video_template9,
-               &cx25821_video_template10,
-               &cx25821_video_template11,
-               &cx25821_videoioctl_template,
-       };
-
        printk(KERN_INFO "\n***********************************\n");
        printk(KERN_INFO "cx25821 set up\n");
        printk(KERN_INFO "***********************************\n\n");
@@ -947,7 +931,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
 
        /* Apply a sensible clock frequency for the PCIe bridge */
        dev->clk_freq = 28000000;
-       dev->sram_channels = cx25821_sram_channels;
+       for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
+              dev->channels[i].sram_channels = &cx25821_sram_channels[i];
 
        if (dev->nr > 1)
                CX25821_INFO("dev->nr > 1!");
@@ -970,7 +955,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
        dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
        dev->i2c_bus[0].i2c_period = (0x07 << 24);      /* 1.95MHz */
 
-
        if (cx25821_get_resources(dev) < 0) {
                printk(KERN_ERR "%s No more PCIe resources for "
                       "subsystem: %04x:%04x\n",
@@ -1018,37 +1002,24 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
                     dev->i2c_bus[0].i2c_rc);
 
        cx25821_card_setup(dev);
-       medusa_video_init(dev);
 
-       for (i = 0; i < VID_CHANNEL_NUM; i++) {
-               if (cx25821_video_register(dev, i, video_template[i]) < 0) {
-                       printk(KERN_ERR
-                              "%s() Failed to register analog video adapters on VID channel %d\n",
-                              __func__, i);
-               }
-       }
+       if (medusa_video_init(dev) < 0)
+              CX25821_ERR("%s() Failed to initialize medusa!\n"
+              , __func__);
 
-       for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
-            i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
-               /* Since we don't have template8 for Audio Downstream */
-               if (cx25821_video_register(dev, i, video_template[i - 1]) < 0) {
-                       printk(KERN_ERR
-                              "%s() Failed to register analog video adapters for Upstream channel %d.\n",
-                              __func__, i);
-               }
-       }
+       cx25821_video_register(dev);
 
        /* register IOCTL device */
        dev->ioctl_dev =
-           cx25821_vdev_init(dev, dev->pci, video_template[VIDEO_IOCTL_CH],
+          cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template,
                              "video");
 
        if (video_register_device
            (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
                cx25821_videoioctl_unregister(dev);
                printk(KERN_ERR
-                      "%s() Failed to register video adapter for IOCTL so releasing.\n",
-                      __func__);
+                  "%s() Failed to register video adapter for IOCTL, so \
+                  unregistering videoioctl device.\n", __func__);
        }
 
        cx25821_dev_checkrevision(dev);
@@ -1349,7 +1320,7 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
 
        BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb, 0, 0);
-       videobuf_dma_unmap(q, dma);
+       videobuf_dma_unmap(q->dev, dma);
        videobuf_dma_free(dma);
        btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1371,7 +1342,8 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
 
        for (i = 0; i < VID_CHANNEL_NUM; i++) {
                if (pci_status & mask[i]) {
-                       vid_status = cx_read(dev->sram_channels[i].int_stat);
+                      vid_status = cx_read(dev->channels[i].
+                              sram_channels->int_stat);
 
                        if (vid_status)
                                handled +=
index 08f45b52df6a817f6e781726093b36f7d14eb67d..e43572e61eceac239f6e86dbd654a34ea95e5fe2 100644 (file)
@@ -282,6 +282,9 @@ static u32 cx25821_functionality(struct i2c_adapter *adap)
 static struct i2c_algorithm cx25821_i2c_algo_template = {
        .master_xfer = i2c_xfer,
        .functionality = cx25821_functionality,
+#ifdef NEED_ALGO_CONTROL
+       .algo_control = dummy_algo_control,
+#endif
 };
 
 static struct i2c_adapter cx25821_i2c_adap_template = {
index b0d216ba7f814631ae99fbc00398fccd8f53a685..60d197f575560ab69ea79e49635b47019094b6c0 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _MEDUSA_DEF_H_
 #define _MEDUSA_DEF_H_
 
-// Video deocder that we supported
+/* Video deocder that we supported */
 #define VDEC_A         0
 #define VDEC_B         1
 #define VDEC_C         2
 #define VDEC_G         6
 #define VDEC_H         7
 
-//#define AUTO_SWITCH_BIT[]  = { 8, 9, 10, 11, 12, 13, 14, 15 };
-
-// The following bit position enables automatic source switching for decoder A-H.
-// Display index per camera.
-//#define VDEC_INDEX[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
-
-// Select input bit to video decoder A-H.
-//#define CH_SRC_SEL_BIT[] = {24, 25, 26, 27, 28, 29, 30, 31};
-
-// end of display sequence
+/* end of display sequence */
 #define END_OF_SEQ                                     0xF;
 
-// registry string size
+/* registry string size */
 #define MAX_REGISTRY_SZ                                        40;
 
 #endif
index 12c90f831b22b4940609e7345c6f1093686adc4d..f7f33b3e705882251daf2e99fbb19bf2c281cb96 100644 (file)
 #ifndef __MEDUSA_REGISTERS__
 #define __MEDUSA_REGISTERS__
 
-// Serial Slave Registers
+/* Serial Slave Registers */
 #define        HOST_REGISTER1                          0x0000
 #define        HOST_REGISTER2                          0x0001
 
-// Chip Configuration Registers
+/* Chip Configuration Registers */
 #define        CHIP_CTRL                                       0x0100
 #define        AFE_AB_CTRL                                     0x0104
 #define        AFE_CD_CTRL                                     0x0108
@@ -92,7 +92,7 @@
 #define        ABIST_CLAMP_E                           0x01F4
 #define        ABIST_CLAMP_F                           0x01F8
 
-//              Digital Video Encoder A Registers
+/*              Digital Video Encoder A Registers */
 #define        DENC_A_REG_1                                    0x0200
 #define        DENC_A_REG_2                                    0x0204
 #define        DENC_A_REG_3                                    0x0208
 #define        DENC_A_REG_7                                    0x0218
 #define        DENC_A_REG_8                                    0x021C
 
-//      Digital Video Encoder B Registers
+/*      Digital Video Encoder B Registers */
 #define        DENC_B_REG_1                                    0x0300
 #define        DENC_B_REG_2                                    0x0304
 #define        DENC_B_REG_3                                    0x0308
 #define        DENC_B_REG_7                                    0x0318
 #define        DENC_B_REG_8                                    0x031C
 
-//              Video Decoder A Registers
+/*              Video Decoder A Registers */
 #define        MODE_CTRL                                               0x1000
 #define        OUT_CTRL1                                               0x1004
 #define        OUT_CTRL_NS                                             0x1008
 #define        VERSION                                                 0x11F8
 #define        SOFT_RST_CTRL                                   0x11FC
 
-//      Video Decoder B Registers
+/*      Video Decoder B Registers */
 #define        VDEC_B_MODE_CTRL                                0x1200
 #define        VDEC_B_OUT_CTRL1                                0x1204
 #define        VDEC_B_OUT_CTRL_NS                              0x1208
 #define        VDEC_B_VERSION                                  0x13F8
 #define        VDEC_B_SOFT_RST_CTRL                    0x13FC
 
-// Video Decoder C Registers
+/* Video Decoder C Registers */
 #define        VDEC_C_MODE_CTRL                                0x1400
 #define        VDEC_C_OUT_CTRL1                                0x1404
 #define        VDEC_C_OUT_CTRL_NS                              0x1408
 #define        VDEC_C_VERSION                                  0x15F8
 #define        VDEC_C_SOFT_RST_CTRL                    0x15FC
 
-// Video Decoder D Registers
+/* Video Decoder D Registers */
 #define VDEC_D_MODE_CTRL                               0x1600
 #define VDEC_D_OUT_CTRL1                               0x1604
 #define VDEC_D_OUT_CTRL_NS                             0x1608
 #define VDEC_D_VERSION                                 0x17F8
 #define VDEC_D_SOFT_RST_CTRL                   0x17FC
 
-// Video Decoder E Registers
+/* Video Decoder E Registers */
 #define        VDEC_E_MODE_CTRL                                0x1800
 #define        VDEC_E_OUT_CTRL1                                0x1804
 #define        VDEC_E_OUT_CTRL_NS                              0x1808
 #define        VDEC_E_VERSION                                  0x19F8
 #define        VDEC_E_SOFT_RST_CTRL                    0x19FC
 
-// Video Decoder F Registers
+/* Video Decoder F Registers */
 #define        VDEC_F_MODE_CTRL                                0x1A00
 #define        VDEC_F_OUT_CTRL1                                0x1A04
 #define        VDEC_F_OUT_CTRL_NS                              0x1A08
 #define        VDEC_F_VERSION                                  0x1BF8
 #define        VDEC_F_SOFT_RST_CTRL                    0x1BFC
 
-// Video Decoder G Registers
+/* Video Decoder G Registers */
 #define        VDEC_G_MODE_CTRL                                0x1C00
 #define        VDEC_G_OUT_CTRL1                                0x1C04
 #define        VDEC_G_OUT_CTRL_NS                              0x1C08
 #define        VDEC_G_VERSION                                  0x1DF8
 #define        VDEC_G_SOFT_RST_CTRL                    0x1DFC
 
-//              Video Decoder H Registers
+/*              Video Decoder H Registers  */
 #define        VDEC_H_MODE_CTRL                                0x1E00
 #define        VDEC_H_OUT_CTRL1                                0x1E04
 #define        VDEC_H_OUT_CTRL_NS                              0x1E08
 #define        VDEC_H_VERSION                                  0x1FF8
 #define        VDEC_H_SOFT_RST_CTRL                    0x1FFC
 
-//*****************************************************************************
-// LUMA_CTRL register fields
+/*****************************************************************************/
+/* LUMA_CTRL register fields */
 #define VDEC_A_BRITE_CTRL                              0x1014
 #define VDEC_A_CNTRST_CTRL                     0x1015
 #define VDEC_A_PEAK_SEL                        0x1016
 
-//*****************************************************************************
-// CHROMA_CTRL register fields
+/*****************************************************************************/
+/* CHROMA_CTRL register fields */
 #define VDEC_A_USAT_CTRL                       0x1018
 #define VDEC_A_VSAT_CTRL                       0x1019
 #define VDEC_A_HUE_CTRL                        0x101A
index 34616dc507f9f580c8e03fcf6a4b58171f4d7b41..ef9f2b82a860ec14aa476cdf4371a29d57f1a1f2 100644 (file)
@@ -778,9 +778,9 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
 
 int medusa_video_init(struct cx25821_dev *dev)
 {
-       u32 value, tmp = 0;
-       int ret_val;
-       int i;
+       u32 value = 0, tmp = 0;
+       int ret_val = 0;
+       int i = 0;
 
        mutex_lock(&dev->lock);
 
@@ -790,6 +790,7 @@ int medusa_video_init(struct cx25821_dev *dev)
        value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
        value &= 0xFFFFF0FF;
        ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
        if (ret_val < 0)
                goto error;
 
@@ -797,6 +798,7 @@ int medusa_video_init(struct cx25821_dev *dev)
        value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
        value &= 0xFFFFFFDF;
        ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
        if (ret_val < 0)
                goto error;
 
@@ -812,6 +814,7 @@ int medusa_video_init(struct cx25821_dev *dev)
        value &= 0xFF70FF70;
        value |= 0x00090008;    /* set en_active */
        ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value);
+
        if (ret_val < 0)
                goto error;
 
@@ -826,8 +829,10 @@ int medusa_video_init(struct cx25821_dev *dev)
        /* select AFE clock to output mode */
        value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
        value &= 0x83FFFFFF;
-       ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
-                                   value | 0x10000000);
+       ret_val =
+          cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+                            value | 0x10000000);
+
        if (ret_val < 0)
                goto error;
 
@@ -849,12 +854,15 @@ int medusa_video_init(struct cx25821_dev *dev)
 
        value |= 7;
        ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value);
+
        if (ret_val < 0)
                goto error;
 
+
        mutex_unlock(&dev->lock);
 
        ret_val = medusa_set_videostandard(dev);
+
        return ret_val;
 
 error:
index 2fab4b2f251cf6b06066981f7f004ae87dfab59d..6175e09618557ac5bbba50d9413b1e370db4d8ee 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "cx25821-medusa-defines.h"
 
-// Color control constants
+/* Color control constants */
 #define VIDEO_PROCAMP_MIN                 0
 #define VIDEO_PROCAMP_MAX                 10000
 #define UNSIGNED_BYTE_MIN                 0
@@ -33,7 +33,7 @@
 #define SIGNED_BYTE_MIN                   -128
 #define SIGNED_BYTE_MAX                   127
 
-// Default video color settings
+/* Default video color settings */
 #define SHARPNESS_DEFAULT                 50
 #define SATURATION_DEFAULT              5000
 #define BRIGHTNESS_DEFAULT              6200
index 7241e7ee3fd3c5e13b4ea703be2abc3187c391f0..cfe0f32db37751f0902ee89ae84674468c4c2c58 100644 (file)
 #define RISC_SYNC_EVEN_VBI      0x00000207
 #define RISC_NOOP                       0xF0000000
 
-//*****************************************************************************
-// ASB SRAM
-//*****************************************************************************
-#define  TX_SRAM                   0x000000    // Transmit SRAM
-
-//*****************************************************************************
-#define  RX_RAM                    0x010000    // Receive SRAM
-
-//*****************************************************************************
-// Application Layer (AL)
-//*****************************************************************************
-#define  DEV_CNTRL2                0x040000    // Device control
+/*****************************************************************************
+* ASB SRAM
+ *****************************************************************************/
+#define  TX_SRAM                   0x000000    /* Transmit SRAM */
+
+/*****************************************************************************/
+#define  RX_RAM                    0x010000    /* Receive SRAM */
+
+/*****************************************************************************
+* Application Layer (AL)
+ *****************************************************************************/
+#define  DEV_CNTRL2                0x040000    /* Device control */
 #define  FLD_RUN_RISC              0x00000020
 
-//*****************************************************************************
-#define  PCI_INT_MSK               0x040010    // PCI interrupt mask
-#define  PCI_INT_STAT              0x040014    // PCI interrupt status
-#define  PCI_INT_MSTAT             0x040018    // PCI interrupt masked status
+/* ***************************************************************************** */
+#define  PCI_INT_MSK               0x040010    /* PCI interrupt mask */
+#define  PCI_INT_STAT              0x040014    /* PCI interrupt status */
+#define  PCI_INT_MSTAT             0x040018    /* PCI interrupt masked status */
 #define  FLD_HAMMERHEAD_INT        (1 << 27)
 #define  FLD_UART_INT              (1 << 26)
 #define  FLD_IRQN_INT              (1 << 25)
 #define  FLD_VID_B_INT             (1 << 1)
 #define  FLD_VID_A_INT             (1 << 0)
 
-//*****************************************************************************
-#define  VID_A_INT_MSK             0x040020    // Video A interrupt mask
-#define  VID_A_INT_STAT            0x040024    // Video A interrupt status
-#define  VID_A_INT_MSTAT           0x040028    // Video A interrupt masked status
-#define  VID_A_INT_SSTAT           0x04002C    // Video A interrupt set status
-
-//*****************************************************************************
-#define  VID_B_INT_MSK             0x040030    // Video B interrupt mask
-#define  VID_B_INT_STAT            0x040034    // Video B interrupt status
-#define  VID_B_INT_MSTAT           0x040038    // Video B interrupt masked status
-#define  VID_B_INT_SSTAT           0x04003C    // Video B interrupt set status
-
-//*****************************************************************************
-#define  VID_C_INT_MSK             0x040040    // Video C interrupt mask
-#define  VID_C_INT_STAT            0x040044    // Video C interrupt status
-#define  VID_C_INT_MSTAT           0x040048    // Video C interrupt masked status
-#define  VID_C_INT_SSTAT           0x04004C    // Video C interrupt set status
-
-//*****************************************************************************
-#define  VID_D_INT_MSK             0x040050    // Video D interrupt mask
-#define  VID_D_INT_STAT            0x040054    // Video D interrupt status
-#define  VID_D_INT_MSTAT           0x040058    // Video D interrupt masked status
-#define  VID_D_INT_SSTAT           0x04005C    // Video D interrupt set status
-
-//*****************************************************************************
-#define  VID_E_INT_MSK             0x040060    // Video E interrupt mask
-#define  VID_E_INT_STAT            0x040064    // Video E interrupt status
-#define  VID_E_INT_MSTAT           0x040068    // Video E interrupt masked status
-#define  VID_E_INT_SSTAT           0x04006C    // Video E interrupt set status
-
-//*****************************************************************************
-#define  VID_F_INT_MSK             0x040070    // Video F interrupt mask
-#define  VID_F_INT_STAT            0x040074    // Video F interrupt status
-#define  VID_F_INT_MSTAT           0x040078    // Video F interrupt masked status
-#define  VID_F_INT_SSTAT           0x04007C    // Video F interrupt set status
-
-//*****************************************************************************
-#define  VID_G_INT_MSK             0x040080    // Video G interrupt mask
-#define  VID_G_INT_STAT            0x040084    // Video G interrupt status
-#define  VID_G_INT_MSTAT           0x040088    // Video G interrupt masked status
-#define  VID_G_INT_SSTAT           0x04008C    // Video G interrupt set status
-
-//*****************************************************************************
-#define  VID_H_INT_MSK             0x040090    // Video H interrupt mask
-#define  VID_H_INT_STAT            0x040094    // Video H interrupt status
-#define  VID_H_INT_MSTAT           0x040098    // Video H interrupt masked status
-#define  VID_H_INT_SSTAT           0x04009C    // Video H interrupt set status
-
-//*****************************************************************************
-#define  VID_I_INT_MSK             0x0400A0    // Video I interrupt mask
-#define  VID_I_INT_STAT            0x0400A4    // Video I interrupt status
-#define  VID_I_INT_MSTAT           0x0400A8    // Video I interrupt masked status
-#define  VID_I_INT_SSTAT           0x0400AC    // Video I interrupt set status
-
-//*****************************************************************************
-#define  VID_J_INT_MSK             0x0400B0    // Video J interrupt mask
-#define  VID_J_INT_STAT            0x0400B4    // Video J interrupt status
-#define  VID_J_INT_MSTAT           0x0400B8    // Video J interrupt masked status
-#define  VID_J_INT_SSTAT           0x0400BC    // Video J interrupt set status
+/* ***************************************************************************** */
+#define  VID_A_INT_MSK             0x040020    /* Video A interrupt mask */
+#define  VID_A_INT_STAT            0x040024    /* Video A interrupt status */
+#define  VID_A_INT_MSTAT           0x040028    /* Video A interrupt masked status */
+#define  VID_A_INT_SSTAT           0x04002C    /* Video A interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_B_INT_MSK             0x040030    /* Video B interrupt mask */
+#define  VID_B_INT_STAT            0x040034    /* Video B interrupt status */
+#define  VID_B_INT_MSTAT           0x040038    /* Video B interrupt masked status */
+#define  VID_B_INT_SSTAT           0x04003C    /* Video B interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_C_INT_MSK             0x040040    /* Video C interrupt mask */
+#define  VID_C_INT_STAT            0x040044    /* Video C interrupt status */
+#define  VID_C_INT_MSTAT           0x040048    /* Video C interrupt masked status */
+#define  VID_C_INT_SSTAT           0x04004C    /* Video C interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_D_INT_MSK             0x040050    /* Video D interrupt mask */
+#define  VID_D_INT_STAT            0x040054    /* Video D interrupt status */
+#define  VID_D_INT_MSTAT           0x040058    /* Video D interrupt masked status */
+#define  VID_D_INT_SSTAT           0x04005C    /* Video D interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_E_INT_MSK             0x040060    /* Video E interrupt mask */
+#define  VID_E_INT_STAT            0x040064    /* Video E interrupt status */
+#define  VID_E_INT_MSTAT           0x040068    /* Video E interrupt masked status */
+#define  VID_E_INT_SSTAT           0x04006C    /* Video E interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_F_INT_MSK             0x040070    /* Video F interrupt mask */
+#define  VID_F_INT_STAT            0x040074    /* Video F interrupt status */
+#define  VID_F_INT_MSTAT           0x040078    /* Video F interrupt masked status */
+#define  VID_F_INT_SSTAT           0x04007C    /* Video F interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_G_INT_MSK             0x040080    /* Video G interrupt mask */
+#define  VID_G_INT_STAT            0x040084    /* Video G interrupt status */
+#define  VID_G_INT_MSTAT           0x040088    /* Video G interrupt masked status */
+#define  VID_G_INT_SSTAT           0x04008C    /* Video G interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_H_INT_MSK             0x040090    /* Video H interrupt mask */
+#define  VID_H_INT_STAT            0x040094    /* Video H interrupt status */
+#define  VID_H_INT_MSTAT           0x040098    /* Video H interrupt masked status */
+#define  VID_H_INT_SSTAT           0x04009C    /* Video H interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_I_INT_MSK             0x0400A0    /* Video I interrupt mask */
+#define  VID_I_INT_STAT            0x0400A4    /* Video I interrupt status */
+#define  VID_I_INT_MSTAT           0x0400A8    /* Video I interrupt masked status */
+#define  VID_I_INT_SSTAT           0x0400AC    /* Video I interrupt set status */
+
+/* ***************************************************************************** */
+#define  VID_J_INT_MSK             0x0400B0    /* Video J interrupt mask */
+#define  VID_J_INT_STAT            0x0400B4    /* Video J interrupt status */
+#define  VID_J_INT_MSTAT           0x0400B8    /* Video J interrupt masked status */
+#define  VID_J_INT_SSTAT           0x0400BC    /* Video J interrupt set status */
 
 #define  FLD_VID_SRC_OPC_ERR       0x00020000
 #define  FLD_VID_DST_OPC_ERR       0x00010000
 #define  FLD_VID_SRC_ERRORS            FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF
 #define  FLD_VID_DST_ERRORS            FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF
 
-//*****************************************************************************
-#define  AUD_A_INT_MSK             0x0400C0    // Audio Int interrupt mask
-#define  AUD_A_INT_STAT            0x0400C4    // Audio Int interrupt status
-#define  AUD_A_INT_MSTAT           0x0400C8    // Audio Int interrupt masked status
-#define  AUD_A_INT_SSTAT           0x0400CC    // Audio Int interrupt set status
-
-//*****************************************************************************
-#define  AUD_B_INT_MSK             0x0400D0    // Audio Int interrupt mask
-#define  AUD_B_INT_STAT            0x0400D4    // Audio Int interrupt status
-#define  AUD_B_INT_MSTAT           0x0400D8    // Audio Int interrupt masked status
-#define  AUD_B_INT_SSTAT           0x0400DC    // Audio Int interrupt set status
-
-//*****************************************************************************
-#define  AUD_C_INT_MSK             0x0400E0    // Audio Int interrupt mask
-#define  AUD_C_INT_STAT            0x0400E4    // Audio Int interrupt status
-#define  AUD_C_INT_MSTAT           0x0400E8    // Audio Int interrupt masked status
-#define  AUD_C_INT_SSTAT           0x0400EC    // Audio Int interrupt set status
-
-//*****************************************************************************
-#define  AUD_D_INT_MSK             0x0400F0    // Audio Int interrupt mask
-#define  AUD_D_INT_STAT            0x0400F4    // Audio Int interrupt status
-#define  AUD_D_INT_MSTAT           0x0400F8    // Audio Int interrupt masked status
-#define  AUD_D_INT_SSTAT           0x0400FC    // Audio Int interrupt set status
-
-//*****************************************************************************
-#define  AUD_E_INT_MSK             0x040100    // Audio Int interrupt mask
-#define  AUD_E_INT_STAT            0x040104    // Audio Int interrupt status
-#define  AUD_E_INT_MSTAT           0x040108    // Audio Int interrupt masked status
-#define  AUD_E_INT_SSTAT           0x04010C    // Audio Int interrupt set status
+/* ***************************************************************************** */
+#define  AUD_A_INT_MSK             0x0400C0    /* Audio Int interrupt mask */
+#define  AUD_A_INT_STAT            0x0400C4    /* Audio Int interrupt status */
+#define  AUD_A_INT_MSTAT           0x0400C8    /* Audio Int interrupt masked status */
+#define  AUD_A_INT_SSTAT           0x0400CC    /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_B_INT_MSK             0x0400D0    /* Audio Int interrupt mask */
+#define  AUD_B_INT_STAT            0x0400D4    /* Audio Int interrupt status */
+#define  AUD_B_INT_MSTAT           0x0400D8    /* Audio Int interrupt masked status */
+#define  AUD_B_INT_SSTAT           0x0400DC    /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_C_INT_MSK             0x0400E0    /* Audio Int interrupt mask */
+#define  AUD_C_INT_STAT            0x0400E4    /* Audio Int interrupt status */
+#define  AUD_C_INT_MSTAT           0x0400E8    /* Audio Int interrupt masked status */
+#define  AUD_C_INT_SSTAT           0x0400EC    /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_D_INT_MSK             0x0400F0    /* Audio Int interrupt mask */
+#define  AUD_D_INT_STAT            0x0400F4    /* Audio Int interrupt status */
+#define  AUD_D_INT_MSTAT           0x0400F8    /* Audio Int interrupt masked status */
+#define  AUD_D_INT_SSTAT           0x0400FC    /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define  AUD_E_INT_MSK             0x040100    /* Audio Int interrupt mask */
+#define  AUD_E_INT_STAT            0x040104    /* Audio Int interrupt status */
+#define  AUD_E_INT_MSTAT           0x040108    /* Audio Int interrupt masked status */
+#define  AUD_E_INT_SSTAT           0x04010C    /* Audio Int interrupt set status */
 
 #define  FLD_AUD_SRC_OPC_ERR       0x00020000
 #define  FLD_AUD_DST_OPC_ERR       0x00010000
 #define  FLD_AUD_SRC_RISCI1        0x00000002
 #define  FLD_AUD_DST_RISCI1        0x00000001
 
-//*****************************************************************************
-#define  MBIF_A_INT_MSK             0x040110   // MBIF Int interrupt mask
-#define  MBIF_A_INT_STAT            0x040114   // MBIF Int interrupt status
-#define  MBIF_A_INT_MSTAT           0x040118   // MBIF Int interrupt masked status
-#define  MBIF_A_INT_SSTAT           0x04011C   // MBIF Int interrupt set status
+/* ***************************************************************************** */
+#define  MBIF_A_INT_MSK             0x040110   /* MBIF Int interrupt mask */
+#define  MBIF_A_INT_STAT            0x040114   /* MBIF Int interrupt status */
+#define  MBIF_A_INT_MSTAT           0x040118   /* MBIF Int interrupt masked status */
+#define  MBIF_A_INT_SSTAT           0x04011C   /* MBIF Int interrupt set status */
 
-//*****************************************************************************
-#define  MBIF_B_INT_MSK             0x040120   // MBIF Int interrupt mask
-#define  MBIF_B_INT_STAT            0x040124   // MBIF Int interrupt status
-#define  MBIF_B_INT_MSTAT           0x040128   // MBIF Int interrupt masked status
-#define  MBIF_B_INT_SSTAT           0x04012C   // MBIF Int interrupt set status
+/* ***************************************************************************** */
+#define  MBIF_B_INT_MSK             0x040120   /* MBIF Int interrupt mask */
+#define  MBIF_B_INT_STAT            0x040124   /* MBIF Int interrupt status */
+#define  MBIF_B_INT_MSTAT           0x040128   /* MBIF Int interrupt masked status */
+#define  MBIF_B_INT_SSTAT           0x04012C   /* MBIF Int interrupt set status */
 
 #define  FLD_MBIF_DST_OPC_ERR       0x00010000
 #define  FLD_MBIF_DST_SYNC          0x00001000
 #define  FLD_MBIF_DST_RISCI2        0x00000010
 #define  FLD_MBIF_DST_RISCI1        0x00000001
 
-//*****************************************************************************
-#define  AUD_EXT_INT_MSK           0x040060    // Audio Ext interrupt mask
-#define  AUD_EXT_INT_STAT          0x040064    // Audio Ext interrupt status
-#define  AUD_EXT_INT_MSTAT         0x040068    // Audio Ext interrupt masked status
-#define  AUD_EXT_INT_SSTAT         0x04006C    // Audio Ext interrupt set status
+/* ***************************************************************************** */
+#define  AUD_EXT_INT_MSK           0x040060    /* Audio Ext interrupt mask */
+#define  AUD_EXT_INT_STAT          0x040064    /* Audio Ext interrupt status */
+#define  AUD_EXT_INT_MSTAT         0x040068    /* Audio Ext interrupt masked status */
+#define  AUD_EXT_INT_SSTAT         0x04006C    /* Audio Ext interrupt set status */
 #define  FLD_AUD_EXT_OPC_ERR       0x00010000
 #define  FLD_AUD_EXT_SYNC          0x00001000
 #define  FLD_AUD_EXT_OF            0x00000100
 #define  FLD_AUD_EXT_RISCI2        0x00000010
 #define  FLD_AUD_EXT_RISCI1        0x00000001
 
-//*****************************************************************************
-#define  GPIO_LO                   0x110010    // Lower  of GPIO pins [31:0]
-#define  GPIO_HI                   0x110014    // Upper WORD  of GPIO pins [47:31]
+/* ***************************************************************************** */
+#define  GPIO_LO                   0x110010    /* Lower  of GPIO pins [31:0] */
+#define  GPIO_HI                   0x110014    /* Upper WORD  of GPIO pins [47:31] */
 
-#define  GPIO_LO_OE                0x110018    // Lower  of GPIO output enable [31:0]
-#define  GPIO_HI_OE                0x11001C    // Upper word  of GPIO output enable [47:32]
+#define  GPIO_LO_OE                0x110018    /* Lower  of GPIO output enable [31:0] */
+#define  GPIO_HI_OE                0x11001C    /* Upper word  of GPIO output enable [47:32] */
 
-#define  GPIO_LO_INT_MSK           0x11003C    // GPIO interrupt mask
-#define  GPIO_LO_INT_STAT          0x110044    // GPIO interrupt status
-#define  GPIO_LO_INT_MSTAT         0x11004C    // GPIO interrupt masked status
-#define  GPIO_LO_ISM_SNS           0x110054    // GPIO interrupt sensitivity
-#define  GPIO_LO_ISM_POL           0x11005C    // GPIO interrupt polarity
+#define  GPIO_LO_INT_MSK           0x11003C    /* GPIO interrupt mask */
+#define  GPIO_LO_INT_STAT          0x110044    /* GPIO interrupt status */
+#define  GPIO_LO_INT_MSTAT         0x11004C    /* GPIO interrupt masked status */
+#define  GPIO_LO_ISM_SNS           0x110054    /* GPIO interrupt sensitivity */
+#define  GPIO_LO_ISM_POL           0x11005C    /* GPIO interrupt polarity */
 
-#define  GPIO_HI_INT_MSK           0x110040    // GPIO interrupt mask
-#define  GPIO_HI_INT_STAT          0x110048    // GPIO interrupt status
-#define  GPIO_HI_INT_MSTAT         0x110050    // GPIO interrupt masked status
-#define  GPIO_HI_ISM_SNS           0x110058    // GPIO interrupt sensitivity
-#define  GPIO_HI_ISM_POL           0x110060    // GPIO interrupt polarity
+#define  GPIO_HI_INT_MSK           0x110040    /* GPIO interrupt mask */
+#define  GPIO_HI_INT_STAT          0x110048    /* GPIO interrupt status */
+#define  GPIO_HI_INT_MSTAT         0x110050    /* GPIO interrupt masked status */
+#define  GPIO_HI_ISM_SNS           0x110058    /* GPIO interrupt sensitivity */
+#define  GPIO_HI_ISM_POL           0x110060    /* GPIO interrupt polarity */
 
 #define  FLD_GPIO43_INT            (1 << 11)
 #define  FLD_GPIO42_INT            (1 << 10)
 #define  FLD_GPIO1_INT             (1 << 1)
 #define  FLD_GPIO0_INT             (1 << 0)
 
-//*****************************************************************************
-#define  TC_REQ                    0x040090    // Rider PCI Express traFFic class request
+/* ***************************************************************************** */
+#define  TC_REQ                    0x040090    /* Rider PCI Express traFFic class request */
 
-//*****************************************************************************
-#define  TC_REQ_SET                0x040094    // Rider PCI Express traFFic class request set
+/* ***************************************************************************** */
+#define  TC_REQ_SET                0x040094    /* Rider PCI Express traFFic class request set */
 
-//*****************************************************************************
-// Rider
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Rider */
+/* ***************************************************************************** */
 
-// PCI Compatible Header
-//*****************************************************************************
+/* PCI Compatible Header */
+/* ***************************************************************************** */
 #define  RDR_CFG0                  0x050000
 #define  RDR_VENDOR_DEVICE_ID_CFG  0x050000
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG1                  0x050004
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG2                  0x050008
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG3                  0x05000C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG4                  0x050010
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG5                  0x050014
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG6                  0x050018
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG7                  0x05001C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG8                  0x050020
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG9                  0x050024
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGA                  0x050028
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGB                  0x05002C
 #define  RDR_SUSSYSTEM_ID_CFG      0x05002C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGC                  0x050030
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGD                  0x050034
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGE                  0x050038
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGF                  0x05003C
 
-//*****************************************************************************
-// PCI-Express Capabilities
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PCI-Express Capabilities */
+/* ***************************************************************************** */
 #define  RDR_PECAP                 0x050040
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PEDEVCAP              0x050044
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PEDEVSC               0x050048
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PELINKCAP             0x05004C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PELINKSC              0x050050
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PMICAP                0x050080
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PMCSR                 0x050084
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VPDCAP                0x050090
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VPDDATA               0x050094
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSICAP                0x0500A0
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSIARL                0x0500A4
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSIARU                0x0500A8
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSIDATA               0x0500AC
 
-//*****************************************************************************
-// PCI Express Extended Capabilities
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PCI Express Extended Capabilities */
+/* ***************************************************************************** */
 #define  RDR_AERXCAP               0x050100
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERUESTA              0x050104
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERUEMSK              0x050108
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERUESEV              0x05010C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERCESTA              0x050110
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERCEMSK              0x050114
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERCC                 0x050118
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL0                0x05011C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL1                0x050120
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL2                0x050124
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL3                0x050128
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCXCAP                0x050200
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCCAP1                0x050204
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCCAP2                0x050208
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCSC                  0x05020C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR0_CAP              0x050210
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR0_CTRL             0x050214
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR0_STAT             0x050218
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR1_CAP              0x05021C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR1_CTRL             0x050220
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR1_STAT             0x050224
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR2_CAP              0x050228
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR2_CTRL             0x05022C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR2_STAT             0x050230
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR3_CAP              0x050234
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR3_CTRL             0x050238
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR3_STAT             0x05023C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB0                0x050240
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB1                0x050244
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB2                0x050248
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB3                0x05024C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB4                0x050250
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB5                0x050254
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB6                0x050258
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB7                0x05025C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRSTAT0              0x050300
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRSTAT1              0x050304
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRCTL0               0x050308
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRCTL1               0x05030C
 
-//*****************************************************************************
-// Transaction Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Transaction Layer Registers */
+/* ***************************************************************************** */
 #define  RDR_TLSTAT0               0x050310
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TLSTAT1               0x050314
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TLCTL0                0x050318
 #define  FLD_CFG_UR_CPL_MODE       0x00000040
 #define  FLD_CFG_CORR_ERR_QUITE    0x00000020
 #define  FLD_CFG_RELAX_ORDER_MSK   0x00000002
 #define  FLD_CFG_TAG_ORDER_EN      0x00000001
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TLCTL1                0x05031C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQRCAL               0x050320
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQRCAU               0x050324
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQEPA                0x050328
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQCTRL               0x05032C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQSTAT               0x050330
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TL_TEST               0x050334
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR01_CTL             0x050348
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR23_CTL             0x05034C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR0_FC            0x050350
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR1_FC            0x050354
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR2_FC            0x050358
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR3_FC            0x05035C
 
-//*****************************************************************************
-// Data Link Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Data Link Layer Registers */
+/* ***************************************************************************** */
 #define  RDR_DLLSTAT               0x050360
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_DLLCTRL               0x050364
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REPLAYTO              0x050368
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_ACKLATTO              0x05036C
 
-//*****************************************************************************
-// MAC Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* MAC Layer Registers */
+/* ***************************************************************************** */
 #define  RDR_MACSTAT0              0x050380
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACSTAT1              0x050384
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACCTRL0              0x050388
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACCTRL1              0x05038C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACCTRL2              0x050390
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MAC_LB_DATA           0x050394
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_L0S_EXIT_LAT          0x050398
 
-//*****************************************************************************
-// DMAC
-//*****************************************************************************
-#define  DMA1_PTR1                 0x100000    // DMA Current Ptr : Ch#1
+/* ***************************************************************************** */
+/* DMAC */
+/* ***************************************************************************** */
+#define  DMA1_PTR1                 0x100000    /* DMA Current Ptr : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_PTR1                 0x100004    // DMA Current Ptr : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_PTR1                 0x100004    /* DMA Current Ptr : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_PTR1                 0x100008    // DMA Current Ptr : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_PTR1                 0x100008    /* DMA Current Ptr : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_PTR1                 0x10000C    // DMA Current Ptr : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_PTR1                 0x10000C    /* DMA Current Ptr : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_PTR1                 0x100010    // DMA Current Ptr : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_PTR1                 0x100010    /* DMA Current Ptr : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_PTR1                 0x100014    // DMA Current Ptr : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_PTR1                 0x100014    /* DMA Current Ptr : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_PTR1                 0x100018    // DMA Current Ptr : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_PTR1                 0x100018    /* DMA Current Ptr : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_PTR1                 0x10001C    // DMA Current Ptr : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_PTR1                 0x10001C    /* DMA Current Ptr : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_PTR1                 0x100020    // DMA Current Ptr : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_PTR1                 0x100020    /* DMA Current Ptr : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_PTR1                0x100024    // DMA Current Ptr : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_PTR1                0x100024    /* DMA Current Ptr : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_PTR1                0x100028    // DMA Current Ptr : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_PTR1                0x100028    /* DMA Current Ptr : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_PTR1                0x10002C    // DMA Current Ptr : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_PTR1                0x10002C    /* DMA Current Ptr : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_PTR1                0x100030    // DMA Current Ptr : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_PTR1                0x100030    /* DMA Current Ptr : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_PTR1                0x100034    // DMA Current Ptr : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_PTR1                0x100034    /* DMA Current Ptr : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_PTR1                0x100038    // DMA Current Ptr : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_PTR1                0x100038    /* DMA Current Ptr : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_PTR1                0x10003C    // DMA Current Ptr : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_PTR1                0x10003C    /* DMA Current Ptr : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_PTR1                0x100040    // DMA Current Ptr : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_PTR1                0x100040    /* DMA Current Ptr : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_PTR1                0x100044    // DMA Current Ptr : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_PTR1                0x100044    /* DMA Current Ptr : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_PTR1                0x100048    // DMA Current Ptr : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_PTR1                0x100048    /* DMA Current Ptr : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_PTR1                0x10004C    // DMA Current Ptr : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_PTR1                0x10004C    /* DMA Current Ptr : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_PTR1                0x100050    // DMA Current Ptr : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_PTR1                0x100050    /* DMA Current Ptr : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_PTR1                0x100054    // DMA Current Ptr : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_PTR1                0x100054    /* DMA Current Ptr : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_PTR1                0x100058    // DMA Current Ptr : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_PTR1                0x100058    /* DMA Current Ptr : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_PTR1                0x10005C    // DMA Current Ptr : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_PTR1                0x10005C    /* DMA Current Ptr : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_PTR1                0x100060    // DMA Current Ptr : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_PTR1                0x100060    /* DMA Current Ptr : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_PTR1                0x100064    // DMA Current Ptr : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_PTR1                0x100064    /* DMA Current Ptr : Ch#26 */
 
-//*****************************************************************************
-#define  DMA1_PTR2                 0x100080    // DMA Tab Ptr : Ch#1
+/* ***************************************************************************** */
+#define  DMA1_PTR2                 0x100080    /* DMA Tab Ptr : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_PTR2                 0x100084    // DMA Tab Ptr : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_PTR2                 0x100084    /* DMA Tab Ptr : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_PTR2                 0x100088    // DMA Tab Ptr : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_PTR2                 0x100088    /* DMA Tab Ptr : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_PTR2                 0x10008C    // DMA Tab Ptr : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_PTR2                 0x10008C    /* DMA Tab Ptr : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_PTR2                 0x100090    // DMA Tab Ptr : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_PTR2                 0x100090    /* DMA Tab Ptr : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_PTR2                 0x100094    // DMA Tab Ptr : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_PTR2                 0x100094    /* DMA Tab Ptr : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_PTR2                 0x100098    // DMA Tab Ptr : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_PTR2                 0x100098    /* DMA Tab Ptr : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_PTR2                 0x10009C    // DMA Tab Ptr : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_PTR2                 0x10009C    /* DMA Tab Ptr : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_PTR2                 0x1000A0    // DMA Tab Ptr : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_PTR2                 0x1000A0    /* DMA Tab Ptr : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_PTR2                0x1000A4    // DMA Tab Ptr : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_PTR2                0x1000A4    /* DMA Tab Ptr : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_PTR2                0x1000A8    // DMA Tab Ptr : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_PTR2                0x1000A8    /* DMA Tab Ptr : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_PTR2                0x1000AC    // DMA Tab Ptr : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_PTR2                0x1000AC    /* DMA Tab Ptr : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_PTR2                0x1000B0    // DMA Tab Ptr : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_PTR2                0x1000B0    /* DMA Tab Ptr : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_PTR2                0x1000B4    // DMA Tab Ptr : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_PTR2                0x1000B4    /* DMA Tab Ptr : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_PTR2                0x1000B8    // DMA Tab Ptr : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_PTR2                0x1000B8    /* DMA Tab Ptr : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_PTR2                0x1000BC    // DMA Tab Ptr : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_PTR2                0x1000BC    /* DMA Tab Ptr : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_PTR2                0x1000C0    // DMA Tab Ptr : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_PTR2                0x1000C0    /* DMA Tab Ptr : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_PTR2                0x1000C4    // DMA Tab Ptr : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_PTR2                0x1000C4    /* DMA Tab Ptr : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_PTR2                0x1000C8    // DMA Tab Ptr : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_PTR2                0x1000C8    /* DMA Tab Ptr : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_PTR2                0x1000CC    // DMA Tab Ptr : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_PTR2                0x1000CC    /* DMA Tab Ptr : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_PTR2                0x1000D0    // DMA Tab Ptr : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_PTR2                0x1000D0    /* DMA Tab Ptr : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_PTR2                0x1000D4    // DMA Tab Ptr : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_PTR2                0x1000D4    /* DMA Tab Ptr : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_PTR2                0x1000D8    // DMA Tab Ptr : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_PTR2                0x1000D8    /* DMA Tab Ptr : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_PTR2                0x1000DC    // DMA Tab Ptr : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_PTR2                0x1000DC    /* DMA Tab Ptr : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_PTR2                0x1000E0    // DMA Tab Ptr : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_PTR2                0x1000E0    /* DMA Tab Ptr : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_PTR2                0x1000E4    // DMA Tab Ptr : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_PTR2                0x1000E4    /* DMA Tab Ptr : Ch#26 */
 
-//*****************************************************************************
-#define  DMA1_CNT1                 0x100100    // DMA BuFFer Size : Ch#1
+/* ***************************************************************************** */
+#define  DMA1_CNT1                 0x100100    /* DMA BuFFer Size : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_CNT1                 0x100104    // DMA BuFFer Size : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_CNT1                 0x100104    /* DMA BuFFer Size : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_CNT1                 0x100108    // DMA BuFFer Size : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_CNT1                 0x100108    /* DMA BuFFer Size : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_CNT1                 0x10010C    // DMA BuFFer Size : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_CNT1                 0x10010C    /* DMA BuFFer Size : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_CNT1                 0x100110    // DMA BuFFer Size : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_CNT1                 0x100110    /* DMA BuFFer Size : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_CNT1                 0x100114    // DMA BuFFer Size : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_CNT1                 0x100114    /* DMA BuFFer Size : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_CNT1                 0x100118    // DMA BuFFer Size : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_CNT1                 0x100118    /* DMA BuFFer Size : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_CNT1                 0x10011C    // DMA BuFFer Size : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_CNT1                 0x10011C    /* DMA BuFFer Size : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_CNT1                 0x100120    // DMA BuFFer Size : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_CNT1                 0x100120    /* DMA BuFFer Size : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_CNT1                0x100124    // DMA BuFFer Size : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_CNT1                0x100124    /* DMA BuFFer Size : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_CNT1                0x100128    // DMA BuFFer Size : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_CNT1                0x100128    /* DMA BuFFer Size : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_CNT1                0x10012C    // DMA BuFFer Size : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_CNT1                0x10012C    /* DMA BuFFer Size : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_CNT1                0x100130    // DMA BuFFer Size : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_CNT1                0x100130    /* DMA BuFFer Size : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_CNT1                0x100134    // DMA BuFFer Size : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_CNT1                0x100134    /* DMA BuFFer Size : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_CNT1                0x100138    // DMA BuFFer Size : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_CNT1                0x100138    /* DMA BuFFer Size : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_CNT1                0x10013C    // DMA BuFFer Size : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_CNT1                0x10013C    /* DMA BuFFer Size : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_CNT1                0x100140    // DMA BuFFer Size : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_CNT1                0x100140    /* DMA BuFFer Size : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_CNT1                0x100144    // DMA BuFFer Size : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_CNT1                0x100144    /* DMA BuFFer Size : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_CNT1                0x100148    // DMA BuFFer Size : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_CNT1                0x100148    /* DMA BuFFer Size : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_CNT1                0x10014C    // DMA BuFFer Size : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_CNT1                0x10014C    /* DMA BuFFer Size : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_CNT1                0x100150    // DMA BuFFer Size : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_CNT1                0x100150    /* DMA BuFFer Size : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_CNT1                0x100154    // DMA BuFFer Size : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_CNT1                0x100154    /* DMA BuFFer Size : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_CNT1                0x100158    // DMA BuFFer Size : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_CNT1                0x100158    /* DMA BuFFer Size : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_CNT1                0x10015C    // DMA BuFFer Size : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_CNT1                0x10015C    /* DMA BuFFer Size : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_CNT1                0x100160    // DMA BuFFer Size : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_CNT1                0x100160    /* DMA BuFFer Size : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_CNT1                0x100164    // DMA BuFFer Size : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_CNT1                0x100164    /* DMA BuFFer Size : Ch#26 */
 
-//*****************************************************************************
-#define  DMA1_CNT2                 0x100180    // DMA Table Size : Ch#1
+/* ***************************************************************************** */
+#define  DMA1_CNT2                 0x100180    /* DMA Table Size : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_CNT2                 0x100184    // DMA Table Size : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_CNT2                 0x100184    /* DMA Table Size : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_CNT2                 0x100188    // DMA Table Size : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_CNT2                 0x100188    /* DMA Table Size : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_CNT2                 0x10018C    // DMA Table Size : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_CNT2                 0x10018C    /* DMA Table Size : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_CNT2                 0x100190    // DMA Table Size : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_CNT2                 0x100190    /* DMA Table Size : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_CNT2                 0x100194    // DMA Table Size : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_CNT2                 0x100194    /* DMA Table Size : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_CNT2                 0x100198    // DMA Table Size : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_CNT2                 0x100198    /* DMA Table Size : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_CNT2                 0x10019C    // DMA Table Size : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_CNT2                 0x10019C    /* DMA Table Size : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_CNT2                 0x1001A0    // DMA Table Size : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_CNT2                 0x1001A0    /* DMA Table Size : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_CNT2                0x1001A4    // DMA Table Size : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_CNT2                0x1001A4    /* DMA Table Size : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_CNT2                0x1001A8    // DMA Table Size : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_CNT2                0x1001A8    /* DMA Table Size : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_CNT2                0x1001AC    // DMA Table Size : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_CNT2                0x1001AC    /* DMA Table Size : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_CNT2                0x1001B0    // DMA Table Size : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_CNT2                0x1001B0    /* DMA Table Size : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_CNT2                0x1001B4    // DMA Table Size : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_CNT2                0x1001B4    /* DMA Table Size : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_CNT2                0x1001B8    // DMA Table Size : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_CNT2                0x1001B8    /* DMA Table Size : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_CNT2                0x1001BC    // DMA Table Size : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_CNT2                0x1001BC    /* DMA Table Size : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_CNT2                0x1001C0    // DMA Table Size : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_CNT2                0x1001C0    /* DMA Table Size : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_CNT2                0x1001C4    // DMA Table Size : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_CNT2                0x1001C4    /* DMA Table Size : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_CNT2                0x1001C8    // DMA Table Size : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_CNT2                0x1001C8    /* DMA Table Size : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_CNT2                0x1001CC    // DMA Table Size : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_CNT2                0x1001CC    /* DMA Table Size : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_CNT2                0x1001D0    // DMA Table Size : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_CNT2                0x1001D0    /* DMA Table Size : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_CNT2                0x1001D4    // DMA Table Size : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_CNT2                0x1001D4    /* DMA Table Size : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_CNT2                0x1001D8    // DMA Table Size : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_CNT2                0x1001D8    /* DMA Table Size : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_CNT2                0x1001DC    // DMA Table Size : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_CNT2                0x1001DC    /* DMA Table Size : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_CNT2                0x1001E0    // DMA Table Size : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_CNT2                0x1001E0    /* DMA Table Size : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_CNT2                0x1001E4    // DMA Table Size : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_CNT2                0x1001E4    /* DMA Table Size : Ch#26 */
 
-//*****************************************************************************
- // ITG
-//*****************************************************************************
-#define  TM_CNT_LDW                0x110000    // Timer : Counter low
+/* ***************************************************************************** */
+ /* ITG */
+/* ***************************************************************************** */
+#define  TM_CNT_LDW                0x110000    /* Timer : Counter low */
 
-//*****************************************************************************
-#define  TM_CNT_UW                 0x110004    // Timer : Counter high word
+/* ***************************************************************************** */
+#define  TM_CNT_UW                 0x110004    /* Timer : Counter high word */
 
-//*****************************************************************************
-#define  TM_LMT_LDW                0x110008    // Timer : Limit low
+/* ***************************************************************************** */
+#define  TM_LMT_LDW                0x110008    /* Timer : Limit low */
 
-//*****************************************************************************
-#define  TM_LMT_UW                 0x11000C    // Timer : Limit high word
+/* ***************************************************************************** */
+#define  TM_LMT_UW                 0x11000C    /* Timer : Limit high word */
 
-//*****************************************************************************
-#define  GP0_IO                    0x110010    // GPIO output enables data I/O
-#define  FLD_GP_OE                 0x00FF0000  // GPIO: GP_OE output enable
-#define  FLD_GP_IN                 0x0000FF00  // GPIO: GP_IN status
-#define  FLD_GP_OUT                0x000000FF  // GPIO: GP_OUT control
+/* ***************************************************************************** */
+#define  GP0_IO                    0x110010    /* GPIO output enables data I/O */
+#define  FLD_GP_OE                 0x00FF0000  /* GPIO: GP_OE output enable */
+#define  FLD_GP_IN                 0x0000FF00  /* GPIO: GP_IN status */
+#define  FLD_GP_OUT                0x000000FF  /* GPIO: GP_OUT control */
 
-//*****************************************************************************
-#define  GPIO_ISM                  0x110014    // GPIO interrupt sensitivity mode
+/* ***************************************************************************** */
+#define  GPIO_ISM                  0x110014    /* GPIO interrupt sensitivity mode */
 #define  FLD_GP_ISM_SNS            0x00000070
 #define  FLD_GP_ISM_POL            0x00000007
 
-//*****************************************************************************
-#define  SOFT_RESET                0x11001C    // Output system reset reg
+/* ***************************************************************************** */
+#define  SOFT_RESET                0x11001C    /* Output system reset reg */
 #define  FLD_PECOS_SOFT_RESET      0x00000001
 
-//*****************************************************************************
-#define  MC416_RWD                 0x110020    // MC416 GPIO[18:3] pin
-#define  MC416_OEN                 0x110024    // Output enable of GPIO[18:3]
+/* ***************************************************************************** */
+#define  MC416_RWD                 0x110020    /* MC416 GPIO[18:3] pin */
+#define  MC416_OEN                 0x110024    /* Output enable of GPIO[18:3] */
 #define  MC416_CTL                 0x110028
 
-//*****************************************************************************
-#define  ALT_PIN_OUT_SEL           0x11002C    // Alternate GPIO output select
+/* ***************************************************************************** */
+#define  ALT_PIN_OUT_SEL           0x11002C    /* Alternate GPIO output select */
 
 #define  FLD_ALT_GPIO_OUT_SEL      0xF0000000
-// 0          Disabled <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
-// 8          ATT_IF
+/* 0          Disabled <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+/* 8          ATT_IF */
 
 #define  FLD_AUX_PLL_CLK_ALT_SEL   0x0F000000
-// 0          AUX_PLL_CLK<-- default
-// 1          GPIO[2]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          AUX_PLL_CLK<-- default */
+/* 1          GPIO[2] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_IR_TX_ALT_SEL         0x00F00000
-// 0          IR_TX <-- default
-// 1          GPIO[1]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          IR_TX <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_IR_RX_ALT_SEL         0x000F0000
-// 0          IR_RX <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          IR_RX <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO10_ALT_SEL        0x0000F000
-// 0          GPIO[10] <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[10] <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO2_ALT_SEL         0x00000F00
-// 0          GPIO[2] <-- default
-// 1          GPIO[1]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[2] <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO1_ALT_SEL         0x000000F0
-// 0          GPIO[1] <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[1] <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO0_ALT_SEL         0x0000000F
-// 0          GPIO[0] <-- default
-// 1          GPIO[1]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[0] <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
-#define  ALT_PIN_IN_SEL            0x110030    // Alternate GPIO input select
+#define  ALT_PIN_IN_SEL            0x110030    /* Alternate GPIO input select */
 
 #define  FLD_GPIO10_ALT_IN_SEL     0x0000F000
-// 0          GPIO[10] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
-// 5          GPIO[0]
-// 6          GPIO[1]
-// 7          GPIO[2]
+/* 0          GPIO[10] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
+/* 5          GPIO[0] */
+/* 6          GPIO[1] */
+/* 7          GPIO[2] */
 
 #define  FLD_GPIO2_ALT_IN_SEL      0x00000F00
-// 0          GPIO[2] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
+/* 0          GPIO[2] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
 
 #define  FLD_GPIO1_ALT_IN_SEL      0x000000F0
-// 0          GPIO[1] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
+/* 0          GPIO[1] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
 
 #define  FLD_GPIO0_ALT_IN_SEL      0x0000000F
-// 0          GPIO[0] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
+/* 0          GPIO[0] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
 
-//*****************************************************************************
-#define  TEST_BUS_CTL1             0x110040    // Test bus control register #1
+/* ***************************************************************************** */
+#define  TEST_BUS_CTL1             0x110040    /* Test bus control register #1 */
 
-//*****************************************************************************
-#define  TEST_BUS_CTL2             0x110044    // Test bus control register #2
+/* ***************************************************************************** */
+#define  TEST_BUS_CTL2             0x110044    /* Test bus control register #2 */
 
-//*****************************************************************************
-#define  CLK_DELAY                 0x110048    // Clock delay
-#define  FLD_MOE_CLK_DIS           0x80000000  // Disable MoE clock
+/* ***************************************************************************** */
+#define  CLK_DELAY                 0x110048    /* Clock delay */
+#define  FLD_MOE_CLK_DIS           0x80000000  /* Disable MoE clock */
 
-//*****************************************************************************
-#define  PAD_CTRL                  0x110068    // Pad drive strength control
+/* ***************************************************************************** */
+#define  PAD_CTRL                  0x110068    /* Pad drive strength control */
 
-//*****************************************************************************
-#define  MBIST_CTRL                0x110050    // SRAM memory built-in self test control
+/* ***************************************************************************** */
+#define  MBIST_CTRL                0x110050    /* SRAM memory built-in self test control */
 
-//*****************************************************************************
-#define  MBIST_STAT                0x110054    // SRAM memory built-in self test status
+/* ***************************************************************************** */
+#define  MBIST_STAT                0x110054    /* SRAM memory built-in self test status */
 
-//*****************************************************************************
-// PLL registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PLL registers */
+/* ***************************************************************************** */
 #define  PLL_A_INT_FRAC            0x110088
 #define  PLL_A_POST_STAT_BIST      0x11008C
 #define  PLL_B_INT_FRAC            0x110090
 #define  VID_CH_MODE_SEL           0x110078
 #define  VID_CH_CLK_SEL            0x11007C
 
-//*****************************************************************************
-#define  VBI_A_DMA                 0x130008    // VBI A DMA data port
+/* ***************************************************************************** */
+#define  VBI_A_DMA                 0x130008    /* VBI A DMA data port */
 
-//*****************************************************************************
-#define  VID_A_VIP_CTL             0x130080    // Video A VIP format control
+/* ***************************************************************************** */
+#define  VID_A_VIP_CTL             0x130080    /* Video A VIP format control */
 #define  FLD_VIP_MODE              0x00000001
 
-//*****************************************************************************
-#define  VID_A_PIXEL_FRMT          0x130084    // Video A pixel format
+/* ***************************************************************************** */
+#define  VID_A_PIXEL_FRMT          0x130084    /* Video A pixel format */
 #define  FLD_VID_A_GAMMA_DIS       0x00000008
 #define  FLD_VID_A_FORMAT          0x00000007
 #define  FLD_VID_A_GAMMA_FACTOR    0x00000010
 
-//*****************************************************************************
-#define  VID_A_VBI_CTL             0x130088    // Video A VBI miscellaneous control
+/* ***************************************************************************** */
+#define  VID_A_VBI_CTL             0x130088    /* Video A VBI miscellaneous control */
 #define  FLD_VID_A_VIP_EXT         0x00000003
 
-//*****************************************************************************
-#define  VID_B_DMA                 0x130100    // Video B DMA data port
+/* ***************************************************************************** */
+#define  VID_B_DMA                 0x130100    /* Video B DMA data port */
 
-//*****************************************************************************
-#define  VBI_B_DMA                 0x130108    // VBI B DMA data port
+/* ***************************************************************************** */
+#define  VBI_B_DMA                 0x130108    /* VBI B DMA data port */
 
-//*****************************************************************************
-#define  VID_B_SRC_SEL             0x130144    // Video B source select
+/* ***************************************************************************** */
+#define  VID_B_SRC_SEL             0x130144    /* Video B source select */
 #define  FLD_VID_B_SRC_SEL         0x00000000
 
-//*****************************************************************************
-#define  VID_B_LNGTH               0x130150    // Video B line length
+/* ***************************************************************************** */
+#define  VID_B_LNGTH               0x130150    /* Video B line length */
 #define  FLD_VID_B_LN_LNGTH        0x00000FFF
 
-//*****************************************************************************
-#define  VID_B_VIP_CTL             0x130180    // Video B VIP format control
+/* ***************************************************************************** */
+#define  VID_B_VIP_CTL             0x130180    /* Video B VIP format control */
 
-//*****************************************************************************
-#define  VID_B_PIXEL_FRMT          0x130184    // Video B pixel format
+/* ***************************************************************************** */
+#define  VID_B_PIXEL_FRMT          0x130184    /* Video B pixel format */
 #define  FLD_VID_B_GAMMA_DIS       0x00000008
 #define  FLD_VID_B_FORMAT          0x00000007
 #define  FLD_VID_B_GAMMA_FACTOR    0x00000010
 
-//*****************************************************************************
-#define  VID_C_DMA                 0x130200    // Video C DMA data port
+/* ***************************************************************************** */
+#define  VID_C_DMA                 0x130200    /* Video C DMA data port */
 
-//*****************************************************************************
-#define  VID_C_LNGTH               0x130250    // Video C line length
+/* ***************************************************************************** */
+#define  VID_C_LNGTH               0x130250    /* Video C line length */
 #define  FLD_VID_C_LN_LNGTH        0x00000FFF
 
-//*****************************************************************************
-// Video Destination Channels
-//*****************************************************************************
-
-#define  VID_DST_A_GPCNT           0x130020    // Video A general purpose counter
-#define  VID_DST_B_GPCNT           0x130120    // Video B general purpose counter
-#define  VID_DST_C_GPCNT           0x130220    // Video C general purpose counter
-#define  VID_DST_D_GPCNT           0x130320    // Video D general purpose counter
-#define  VID_DST_E_GPCNT           0x130420    // Video E general purpose counter
-#define  VID_DST_F_GPCNT           0x130520    // Video F general purpose counter
-#define  VID_DST_G_GPCNT           0x130620    // Video G general purpose counter
-#define  VID_DST_H_GPCNT           0x130720    // Video H general purpose counter
-
-//*****************************************************************************
-
-#define  VID_DST_A_GPCNT_CTL       0x130030    // Video A general purpose control
-#define  VID_DST_B_GPCNT_CTL       0x130130    // Video B general purpose control
-#define  VID_DST_C_GPCNT_CTL       0x130230    // Video C general purpose control
-#define  VID_DST_D_GPCNT_CTL       0x130330    // Video D general purpose control
-#define  VID_DST_E_GPCNT_CTL       0x130430    // Video E general purpose control
-#define  VID_DST_F_GPCNT_CTL       0x130530    // Video F general purpose control
-#define  VID_DST_G_GPCNT_CTL       0x130630    // Video G general purpose control
-#define  VID_DST_H_GPCNT_CTL       0x130730    // Video H general purpose control
-
-//*****************************************************************************
-
-#define  VID_DST_A_DMA_CTL         0x130040    // Video A DMA control
-#define  VID_DST_B_DMA_CTL         0x130140    // Video B DMA control
-#define  VID_DST_C_DMA_CTL         0x130240    // Video C DMA control
-#define  VID_DST_D_DMA_CTL         0x130340    // Video D DMA control
-#define  VID_DST_E_DMA_CTL         0x130440    // Video E DMA control
-#define  VID_DST_F_DMA_CTL         0x130540    // Video F DMA control
-#define  VID_DST_G_DMA_CTL         0x130640    // Video G DMA control
-#define  VID_DST_H_DMA_CTL         0x130740    // Video H DMA control
+/* ***************************************************************************** */
+/* Video Destination Channels */
+/* ***************************************************************************** */
+
+#define  VID_DST_A_GPCNT           0x130020    /* Video A general purpose counter */
+#define  VID_DST_B_GPCNT           0x130120    /* Video B general purpose counter */
+#define  VID_DST_C_GPCNT           0x130220    /* Video C general purpose counter */
+#define  VID_DST_D_GPCNT           0x130320    /* Video D general purpose counter */
+#define  VID_DST_E_GPCNT           0x130420    /* Video E general purpose counter */
+#define  VID_DST_F_GPCNT           0x130520    /* Video F general purpose counter */
+#define  VID_DST_G_GPCNT           0x130620    /* Video G general purpose counter */
+#define  VID_DST_H_GPCNT           0x130720    /* Video H general purpose counter */
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_GPCNT_CTL       0x130030    /* Video A general purpose control */
+#define  VID_DST_B_GPCNT_CTL       0x130130    /* Video B general purpose control */
+#define  VID_DST_C_GPCNT_CTL       0x130230    /* Video C general purpose control */
+#define  VID_DST_D_GPCNT_CTL       0x130330    /* Video D general purpose control */
+#define  VID_DST_E_GPCNT_CTL       0x130430    /* Video E general purpose control */
+#define  VID_DST_F_GPCNT_CTL       0x130530    /* Video F general purpose control */
+#define  VID_DST_G_GPCNT_CTL       0x130630    /* Video G general purpose control */
+#define  VID_DST_H_GPCNT_CTL       0x130730    /* Video H general purpose control */
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_DMA_CTL         0x130040    /* Video A DMA control */
+#define  VID_DST_B_DMA_CTL         0x130140    /* Video B DMA control */
+#define  VID_DST_C_DMA_CTL         0x130240    /* Video C DMA control */
+#define  VID_DST_D_DMA_CTL         0x130340    /* Video D DMA control */
+#define  VID_DST_E_DMA_CTL         0x130440    /* Video E DMA control */
+#define  VID_DST_F_DMA_CTL         0x130540    /* Video F DMA control */
+#define  VID_DST_G_DMA_CTL         0x130640    /* Video G DMA control */
+#define  VID_DST_H_DMA_CTL         0x130740    /* Video H DMA control */
 
 #define  FLD_VID_RISC_EN           0x00000010
 #define  FLD_VID_FIFO_EN           0x00000001
 
-//*****************************************************************************
-
-#define  VID_DST_A_VIP_CTL         0x130080    // Video A VIP control
-#define  VID_DST_B_VIP_CTL         0x130180    // Video B VIP control
-#define  VID_DST_C_VIP_CTL         0x130280    // Video C VIP control
-#define  VID_DST_D_VIP_CTL         0x130380    // Video D VIP control
-#define  VID_DST_E_VIP_CTL         0x130480    // Video E VIP control
-#define  VID_DST_F_VIP_CTL         0x130580    // Video F VIP control
-#define  VID_DST_G_VIP_CTL         0x130680    // Video G VIP control
-#define  VID_DST_H_VIP_CTL         0x130780    // Video H VIP control
-
-//*****************************************************************************
-
-#define  VID_DST_A_PIX_FRMT        0x130084    // Video A Pixel format
-#define  VID_DST_B_PIX_FRMT        0x130184    // Video B Pixel format
-#define  VID_DST_C_PIX_FRMT        0x130284    // Video C Pixel format
-#define  VID_DST_D_PIX_FRMT        0x130384    // Video D Pixel format
-#define  VID_DST_E_PIX_FRMT        0x130484    // Video E Pixel format
-#define  VID_DST_F_PIX_FRMT        0x130584    // Video F Pixel format
-#define  VID_DST_G_PIX_FRMT        0x130684    // Video G Pixel format
-#define  VID_DST_H_PIX_FRMT        0x130784    // Video H Pixel format
-
-//*****************************************************************************
-// Video Source Channels
-//*****************************************************************************
-
-#define  VID_SRC_A_GPCNT_CTL       0x130804    // Video A general purpose control
-#define  VID_SRC_B_GPCNT_CTL       0x130904    // Video B general purpose control
-#define  VID_SRC_C_GPCNT_CTL       0x130A04    // Video C general purpose control
-#define  VID_SRC_D_GPCNT_CTL       0x130B04    // Video D general purpose control
-#define  VID_SRC_E_GPCNT_CTL       0x130C04    // Video E general purpose control
-#define  VID_SRC_F_GPCNT_CTL       0x130D04    // Video F general purpose control
-#define  VID_SRC_I_GPCNT_CTL       0x130E04    // Video I general purpose control
-#define  VID_SRC_J_GPCNT_CTL       0x130F04    // Video J general purpose control
-
-//*****************************************************************************
-
-#define  VID_SRC_A_GPCNT           0x130808    // Video A general purpose counter
-#define  VID_SRC_B_GPCNT           0x130908    // Video B general purpose counter
-#define  VID_SRC_C_GPCNT           0x130A08    // Video C general purpose counter
-#define  VID_SRC_D_GPCNT           0x130B08    // Video D general purpose counter
-#define  VID_SRC_E_GPCNT           0x130C08    // Video E general purpose counter
-#define  VID_SRC_F_GPCNT           0x130D08    // Video F general purpose counter
-#define  VID_SRC_I_GPCNT           0x130E08    // Video I general purpose counter
-#define  VID_SRC_J_GPCNT           0x130F08    // Video J general purpose counter
-
-//*****************************************************************************
-
-#define  VID_SRC_A_DMA_CTL         0x13080C    // Video A DMA control
-#define  VID_SRC_B_DMA_CTL         0x13090C    // Video B DMA control
-#define  VID_SRC_C_DMA_CTL         0x130A0C    // Video C DMA control
-#define  VID_SRC_D_DMA_CTL         0x130B0C    // Video D DMA control
-#define  VID_SRC_E_DMA_CTL         0x130C0C    // Video E DMA control
-#define  VID_SRC_F_DMA_CTL         0x130D0C    // Video F DMA control
-#define  VID_SRC_I_DMA_CTL         0x130E0C    // Video I DMA control
-#define  VID_SRC_J_DMA_CTL         0x130F0C    // Video J DMA control
+/* ***************************************************************************** */
+
+#define  VID_DST_A_VIP_CTL         0x130080    /* Video A VIP control */
+#define  VID_DST_B_VIP_CTL         0x130180    /* Video B VIP control */
+#define  VID_DST_C_VIP_CTL         0x130280    /* Video C VIP control */
+#define  VID_DST_D_VIP_CTL         0x130380    /* Video D VIP control */
+#define  VID_DST_E_VIP_CTL         0x130480    /* Video E VIP control */
+#define  VID_DST_F_VIP_CTL         0x130580    /* Video F VIP control */
+#define  VID_DST_G_VIP_CTL         0x130680    /* Video G VIP control */
+#define  VID_DST_H_VIP_CTL         0x130780    /* Video H VIP control */
+
+/* ***************************************************************************** */
+
+#define  VID_DST_A_PIX_FRMT        0x130084    /* Video A Pixel format */
+#define  VID_DST_B_PIX_FRMT        0x130184    /* Video B Pixel format */
+#define  VID_DST_C_PIX_FRMT        0x130284    /* Video C Pixel format */
+#define  VID_DST_D_PIX_FRMT        0x130384    /* Video D Pixel format */
+#define  VID_DST_E_PIX_FRMT        0x130484    /* Video E Pixel format */
+#define  VID_DST_F_PIX_FRMT        0x130584    /* Video F Pixel format */
+#define  VID_DST_G_PIX_FRMT        0x130684    /* Video G Pixel format */
+#define  VID_DST_H_PIX_FRMT        0x130784    /* Video H Pixel format */
+
+/* ***************************************************************************** */
+/* Video Source Channels */
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_GPCNT_CTL       0x130804    /* Video A general purpose control */
+#define  VID_SRC_B_GPCNT_CTL       0x130904    /* Video B general purpose control */
+#define  VID_SRC_C_GPCNT_CTL       0x130A04    /* Video C general purpose control */
+#define  VID_SRC_D_GPCNT_CTL       0x130B04    /* Video D general purpose control */
+#define  VID_SRC_E_GPCNT_CTL       0x130C04    /* Video E general purpose control */
+#define  VID_SRC_F_GPCNT_CTL       0x130D04    /* Video F general purpose control */
+#define  VID_SRC_I_GPCNT_CTL       0x130E04    /* Video I general purpose control */
+#define  VID_SRC_J_GPCNT_CTL       0x130F04    /* Video J general purpose control */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_GPCNT           0x130808    /* Video A general purpose counter */
+#define  VID_SRC_B_GPCNT           0x130908    /* Video B general purpose counter */
+#define  VID_SRC_C_GPCNT           0x130A08    /* Video C general purpose counter */
+#define  VID_SRC_D_GPCNT           0x130B08    /* Video D general purpose counter */
+#define  VID_SRC_E_GPCNT           0x130C08    /* Video E general purpose counter */
+#define  VID_SRC_F_GPCNT           0x130D08    /* Video F general purpose counter */
+#define  VID_SRC_I_GPCNT           0x130E08    /* Video I general purpose counter */
+#define  VID_SRC_J_GPCNT           0x130F08    /* Video J general purpose counter */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_DMA_CTL         0x13080C    /* Video A DMA control */
+#define  VID_SRC_B_DMA_CTL         0x13090C    /* Video B DMA control */
+#define  VID_SRC_C_DMA_CTL         0x130A0C    /* Video C DMA control */
+#define  VID_SRC_D_DMA_CTL         0x130B0C    /* Video D DMA control */
+#define  VID_SRC_E_DMA_CTL         0x130C0C    /* Video E DMA control */
+#define  VID_SRC_F_DMA_CTL         0x130D0C    /* Video F DMA control */
+#define  VID_SRC_I_DMA_CTL         0x130E0C    /* Video I DMA control */
+#define  VID_SRC_J_DMA_CTL         0x130F0C    /* Video J DMA control */
 
 #define  FLD_APB_RISC_EN           0x00000010
 #define  FLD_APB_FIFO_EN           0x00000001
 
-//*****************************************************************************
-
-#define  VID_SRC_A_FMT_CTL         0x130810    // Video A format control
-#define  VID_SRC_B_FMT_CTL         0x130910    // Video B format control
-#define  VID_SRC_C_FMT_CTL         0x130A10    // Video C format control
-#define  VID_SRC_D_FMT_CTL         0x130B10    // Video D format control
-#define  VID_SRC_E_FMT_CTL         0x130C10    // Video E format control
-#define  VID_SRC_F_FMT_CTL         0x130D10    // Video F format control
-#define  VID_SRC_I_FMT_CTL         0x130E10    // Video I format control
-#define  VID_SRC_J_FMT_CTL         0x130F10    // Video J format control
-
-//*****************************************************************************
-
-#define  VID_SRC_A_ACTIVE_CTL1     0x130814    // Video A active control      1
-#define  VID_SRC_B_ACTIVE_CTL1     0x130914    // Video B active control      1
-#define  VID_SRC_C_ACTIVE_CTL1     0x130A14    // Video C active control      1
-#define  VID_SRC_D_ACTIVE_CTL1     0x130B14    // Video D active control      1
-#define  VID_SRC_E_ACTIVE_CTL1     0x130C14    // Video E active control      1
-#define  VID_SRC_F_ACTIVE_CTL1     0x130D14    // Video F active control      1
-#define  VID_SRC_I_ACTIVE_CTL1     0x130E14    // Video I active control      1
-#define  VID_SRC_J_ACTIVE_CTL1     0x130F14    // Video J active control      1
-
-//*****************************************************************************
-
-#define  VID_SRC_A_ACTIVE_CTL2     0x130818    // Video A active control      2
-#define  VID_SRC_B_ACTIVE_CTL2     0x130918    // Video B active control      2
-#define  VID_SRC_C_ACTIVE_CTL2     0x130A18    // Video C active control      2
-#define  VID_SRC_D_ACTIVE_CTL2     0x130B18    // Video D active control      2
-#define  VID_SRC_E_ACTIVE_CTL2     0x130C18    // Video E active control      2
-#define  VID_SRC_F_ACTIVE_CTL2     0x130D18    // Video F active control      2
-#define  VID_SRC_I_ACTIVE_CTL2     0x130E18    // Video I active control      2
-#define  VID_SRC_J_ACTIVE_CTL2     0x130F18    // Video J active control      2
-
-//*****************************************************************************
-
-#define  VID_SRC_A_CDT_SZ          0x13081C    // Video A CDT size
-#define  VID_SRC_B_CDT_SZ          0x13091C    // Video B CDT size
-#define  VID_SRC_C_CDT_SZ          0x130A1C    // Video C CDT size
-#define  VID_SRC_D_CDT_SZ          0x130B1C    // Video D CDT size
-#define  VID_SRC_E_CDT_SZ          0x130C1C    // Video E CDT size
-#define  VID_SRC_F_CDT_SZ          0x130D1C    // Video F CDT size
-#define  VID_SRC_I_CDT_SZ          0x130E1C    // Video I CDT size
-#define  VID_SRC_J_CDT_SZ          0x130F1C    // Video J CDT size
-
-//*****************************************************************************
-// Audio I/F
-//*****************************************************************************
-#define  AUD_DST_A_DMA             0x140000    // Audio Int A DMA data port
-#define  AUD_SRC_A_DMA             0x140008    // Audio Int A DMA data port
-
-#define  AUD_A_GPCNT               0x140010    // Audio Int A gp counter
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_FMT_CTL         0x130810    /* Video A format control */
+#define  VID_SRC_B_FMT_CTL         0x130910    /* Video B format control */
+#define  VID_SRC_C_FMT_CTL         0x130A10    /* Video C format control */
+#define  VID_SRC_D_FMT_CTL         0x130B10    /* Video D format control */
+#define  VID_SRC_E_FMT_CTL         0x130C10    /* Video E format control */
+#define  VID_SRC_F_FMT_CTL         0x130D10    /* Video F format control */
+#define  VID_SRC_I_FMT_CTL         0x130E10    /* Video I format control */
+#define  VID_SRC_J_FMT_CTL         0x130F10    /* Video J format control */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_ACTIVE_CTL1     0x130814    /* Video A active control      1 */
+#define  VID_SRC_B_ACTIVE_CTL1     0x130914    /* Video B active control      1 */
+#define  VID_SRC_C_ACTIVE_CTL1     0x130A14    /* Video C active control      1 */
+#define  VID_SRC_D_ACTIVE_CTL1     0x130B14    /* Video D active control      1 */
+#define  VID_SRC_E_ACTIVE_CTL1     0x130C14    /* Video E active control      1 */
+#define  VID_SRC_F_ACTIVE_CTL1     0x130D14    /* Video F active control      1 */
+#define  VID_SRC_I_ACTIVE_CTL1     0x130E14    /* Video I active control      1 */
+#define  VID_SRC_J_ACTIVE_CTL1     0x130F14    /* Video J active control      1 */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_ACTIVE_CTL2     0x130818    /* Video A active control      2 */
+#define  VID_SRC_B_ACTIVE_CTL2     0x130918    /* Video B active control      2 */
+#define  VID_SRC_C_ACTIVE_CTL2     0x130A18    /* Video C active control      2 */
+#define  VID_SRC_D_ACTIVE_CTL2     0x130B18    /* Video D active control      2 */
+#define  VID_SRC_E_ACTIVE_CTL2     0x130C18    /* Video E active control      2 */
+#define  VID_SRC_F_ACTIVE_CTL2     0x130D18    /* Video F active control      2 */
+#define  VID_SRC_I_ACTIVE_CTL2     0x130E18    /* Video I active control      2 */
+#define  VID_SRC_J_ACTIVE_CTL2     0x130F18    /* Video J active control      2 */
+
+/* ***************************************************************************** */
+
+#define  VID_SRC_A_CDT_SZ          0x13081C    /* Video A CDT size */
+#define  VID_SRC_B_CDT_SZ          0x13091C    /* Video B CDT size */
+#define  VID_SRC_C_CDT_SZ          0x130A1C    /* Video C CDT size */
+#define  VID_SRC_D_CDT_SZ          0x130B1C    /* Video D CDT size */
+#define  VID_SRC_E_CDT_SZ          0x130C1C    /* Video E CDT size */
+#define  VID_SRC_F_CDT_SZ          0x130D1C    /* Video F CDT size */
+#define  VID_SRC_I_CDT_SZ          0x130E1C    /* Video I CDT size */
+#define  VID_SRC_J_CDT_SZ          0x130F1C    /* Video J CDT size */
+
+/* ***************************************************************************** */
+/* Audio I/F */
+/* ***************************************************************************** */
+#define  AUD_DST_A_DMA             0x140000    /* Audio Int A DMA data port */
+#define  AUD_SRC_A_DMA             0x140008    /* Audio Int A DMA data port */
+
+#define  AUD_A_GPCNT               0x140010    /* Audio Int A gp counter */
 #define  FLD_AUD_A_GP_CNT          0x0000FFFF
 
-#define  AUD_A_GPCNT_CTL           0x140014    // Audio Int A gp control
+#define  AUD_A_GPCNT_CTL           0x140014    /* Audio Int A gp control */
 
-#define  AUD_A_LNGTH               0x140018    // Audio Int A line length
+#define  AUD_A_LNGTH               0x140018    /* Audio Int A line length */
 
-#define  AUD_A_CFG                 0x14001C    // Audio Int A configuration
+#define  AUD_A_CFG                 0x14001C    /* Audio Int A configuration */
 
-//*****************************************************************************
-#define  AUD_DST_B_DMA             0x140100    // Audio Int B DMA data port
-#define  AUD_SRC_B_DMA             0x140108    // Audio Int B DMA data port
+/* ***************************************************************************** */
+#define  AUD_DST_B_DMA             0x140100    /* Audio Int B DMA data port */
+#define  AUD_SRC_B_DMA             0x140108    /* Audio Int B DMA data port */
 
-#define  AUD_B_GPCNT               0x140110    // Audio Int B gp counter
+#define  AUD_B_GPCNT               0x140110    /* Audio Int B gp counter */
 #define  FLD_AUD_B_GP_CNT          0x0000FFFF
 
-#define  AUD_B_GPCNT_CTL           0x140114    // Audio Int B gp control
+#define  AUD_B_GPCNT_CTL           0x140114    /* Audio Int B gp control */
 
-#define  AUD_B_LNGTH               0x140118    // Audio Int B line length
+#define  AUD_B_LNGTH               0x140118    /* Audio Int B line length */
 
-#define  AUD_B_CFG                 0x14011C    // Audio Int B configuration
+#define  AUD_B_CFG                 0x14011C    /* Audio Int B configuration */
 
-//*****************************************************************************
-#define  AUD_DST_C_DMA             0x140200    // Audio Int C DMA data port
-#define  AUD_SRC_C_DMA             0x140208    // Audio Int C DMA data port
+/* ***************************************************************************** */
+#define  AUD_DST_C_DMA             0x140200    /* Audio Int C DMA data port */
+#define  AUD_SRC_C_DMA             0x140208    /* Audio Int C DMA data port */
 
-#define  AUD_C_GPCNT               0x140210    // Audio Int C gp counter
+#define  AUD_C_GPCNT               0x140210    /* Audio Int C gp counter */
 #define  FLD_AUD_C_GP_CNT          0x0000FFFF
 
-#define  AUD_C_GPCNT_CTL           0x140214    // Audio Int C gp control
+#define  AUD_C_GPCNT_CTL           0x140214    /* Audio Int C gp control */
 
-#define  AUD_C_LNGTH               0x140218    // Audio Int C line length
+#define  AUD_C_LNGTH               0x140218    /* Audio Int C line length */
 
-#define  AUD_C_CFG                 0x14021C    // Audio Int C configuration
+#define  AUD_C_CFG                 0x14021C    /* Audio Int C configuration */
 
-//*****************************************************************************
-#define  AUD_DST_D_DMA             0x140300    // Audio Int D DMA data port
-#define  AUD_SRC_D_DMA             0x140308    // Audio Int D DMA data port
+/* ***************************************************************************** */
+#define  AUD_DST_D_DMA             0x140300    /* Audio Int D DMA data port */
+#define  AUD_SRC_D_DMA             0x140308    /* Audio Int D DMA data port */
 
-#define  AUD_D_GPCNT               0x140310    // Audio Int D gp counter
+#define  AUD_D_GPCNT               0x140310    /* Audio Int D gp counter */
 #define  FLD_AUD_D_GP_CNT          0x0000FFFF
 
-#define  AUD_D_GPCNT_CTL           0x140314    // Audio Int D gp control
+#define  AUD_D_GPCNT_CTL           0x140314    /* Audio Int D gp control */
 
-#define  AUD_D_LNGTH               0x140318    // Audio Int D line length
+#define  AUD_D_LNGTH               0x140318    /* Audio Int D line length */
 
-#define  AUD_D_CFG                 0x14031C    // Audio Int D configuration
+#define  AUD_D_CFG                 0x14031C    /* Audio Int D configuration */
 
-//*****************************************************************************
-#define  AUD_SRC_E_DMA             0x140400    // Audio Int E DMA data port
+/* ***************************************************************************** */
+#define  AUD_SRC_E_DMA             0x140400    /* Audio Int E DMA data port */
 
-#define  AUD_E_GPCNT               0x140410    // Audio Int E gp counter
+#define  AUD_E_GPCNT               0x140410    /* Audio Int E gp counter */
 #define  FLD_AUD_E_GP_CNT          0x0000FFFF
 
-#define  AUD_E_GPCNT_CTL           0x140414    // Audio Int E gp control
+#define  AUD_E_GPCNT_CTL           0x140414    /* Audio Int E gp control */
 
-#define  AUD_E_CFG                 0x14041C    // Audio Int E configuration
+#define  AUD_E_CFG                 0x14041C    /* Audio Int E configuration */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
 #define  FLD_AUD_DST_LN_LNGTH      0x00000FFF
 
 
 #define  FLD_AUD_SRC_ENABLE        0x00010000
 
-//*****************************************************************************
-#define  AUD_INT_DMA_CTL           0x140500    // Audio Int DMA control
+/* ***************************************************************************** */
+#define  AUD_INT_DMA_CTL           0x140500    /* Audio Int DMA control */
 
 #define  FLD_AUD_SRC_E_RISC_EN     0x00008000
 #define  FLD_AUD_SRC_C_RISC_EN     0x00004000
 #define  FLD_AUD_DST_B_FIFO_EN     0x00000002
 #define  FLD_AUD_DST_A_FIFO_EN     0x00000001
 
-//*****************************************************************************
-//
-//                   Mobilygen Interface Registers
-//
-//*****************************************************************************
-// Mobilygen Interface A
-//*****************************************************************************
-#define  MB_IF_A_DMA               0x150000    // MBIF A DMA data port
-#define  MB_IF_A_GPCN              0x150008    // MBIF A GP counter
+/* ***************************************************************************** */
+/*  */
+/* Mobilygen Interface Registers */
+/*  */
+/* ***************************************************************************** */
+/* Mobilygen Interface A */
+/* ***************************************************************************** */
+#define  MB_IF_A_DMA               0x150000    /* MBIF A DMA data port */
+#define  MB_IF_A_GPCN              0x150008    /* MBIF A GP counter */
 #define  MB_IF_A_GPCN_CTRL         0x15000C
 #define  MB_IF_A_DMA_CTRL          0x150010
 #define  MB_IF_A_LENGTH            0x150014
 #define  MB_IF_A_DATA_STRUCT_D     0x150058
 #define  MB_IF_A_DATA_STRUCT_E     0x15005C
 #define  MB_IF_A_DATA_STRUCT_F     0x150060
-//*****************************************************************************
-// Mobilygen Interface B
-//*****************************************************************************
-#define  MB_IF_B_DMA               0x160000    // MBIF A DMA data port
-#define  MB_IF_B_GPCN              0x160008    // MBIF A GP counter
+/* ***************************************************************************** */
+/* Mobilygen Interface B */
+/* ***************************************************************************** */
+#define  MB_IF_B_DMA               0x160000    /* MBIF A DMA data port */
+#define  MB_IF_B_GPCN              0x160008    /* MBIF A GP counter */
 #define  MB_IF_B_GPCN_CTRL         0x16000C
 #define  MB_IF_B_DMA_CTRL          0x160010
 #define  MB_IF_B_LENGTH            0x160014
 #define  MB_IF_B_DATA_STRUCT_E     0x16005C
 #define  MB_IF_B_DATA_STRUCT_F     0x160060
 
-// MB_DMA_CTRL
+/* MB_DMA_CTRL */
 #define  FLD_MB_IF_RISC_EN         0x00000010
 #define  FLD_MB_IF_FIFO_EN         0x00000001
 
-// MB_LENGTH
+/* MB_LENGTH */
 #define  FLD_MB_IF_LN_LNGTH        0x00000FFF
 
-// MB_HCMD register
+/* MB_HCMD register */
 #define  FLD_MB_HCMD_H_GO          0x80000000
 #define  FLD_MB_HCMD_H_BUSY        0x40000000
 #define  FLD_MB_HCMD_H_DMA_HOLD    0x10000000
 #define  FLD_MB_HCMD_H_ADDR        0x00FF0000
 #define  FLD_MB_HCMD_H_DATA        0x0000FFFF
 
-//*****************************************************************************
-// I2C #1
-//*****************************************************************************
-#define  I2C1_ADDR                 0x180000    // I2C #1 address
-#define  FLD_I2C_DADDR             0xfe000000  // RW [31:25] I2C Device Address
-                                                // RO [24] reserved
-//*****************************************************************************
-#define  FLD_I2C_SADDR             0x00FFFFFF  // RW [23:0]  I2C Sub-address
-
-//*****************************************************************************
-#define  I2C1_WDATA                0x180004    // I2C #1 write data
-#define  FLD_I2C_WDATA             0xFFFFFFFF  // RW [31:0]
-
-//*****************************************************************************
-#define  I2C1_CTRL                 0x180008    // I2C #1 control
-#define  FLD_I2C_PERIOD            0xFF000000  // RW [31:24]
-#define  FLD_I2C_SCL_IN            0x00200000  // RW [21]
-#define  FLD_I2C_SDA_IN            0x00100000  // RW [20]
-                                                // RO [19:18] reserved
-#define  FLD_I2C_SCL_OUT           0x00020000  // RW [17]
-#define  FLD_I2C_SDA_OUT           0x00010000  // RW [16]
-                                                // RO [15] reserved
-#define  FLD_I2C_DATA_LEN          0x00007000  // RW [14:12]
-#define  FLD_I2C_SADDR_INC         0x00000800  // RW [11]
-                                                // RO [10:9] reserved
-#define  FLD_I2C_SADDR_LEN         0x00000300  // RW [9:8]
-                                                // RO [7:6] reserved
-#define  FLD_I2C_SOFT              0x00000020  // RW [5]
-#define  FLD_I2C_NOSTOP            0x00000010  // RW [4]
-#define  FLD_I2C_EXTEND            0x00000008  // RW [3]
-#define  FLD_I2C_SYNC              0x00000004  // RW [2]
-#define  FLD_I2C_READ_SA           0x00000002  // RW [1]
-#define  FLD_I2C_READ_WRN          0x00000001  // RW [0]
-
-//*****************************************************************************
-#define  I2C1_RDATA                0x18000C    // I2C #1 read data
-#define  FLD_I2C_RDATA             0xFFFFFFFF  // RO [31:0]
-
-//*****************************************************************************
-#define  I2C1_STAT                 0x180010    // I2C #1 status
-#define  FLD_I2C_XFER_IN_PROG      0x00000002  // RO [1]
-#define  FLD_I2C_RACK              0x00000001  // RO [0]
-
-//*****************************************************************************
-// I2C #2
-//*****************************************************************************
-#define  I2C2_ADDR                 0x190000    // I2C #2 address
-
-//*****************************************************************************
-#define  I2C2_WDATA                0x190004    // I2C #2 write data
-
-//*****************************************************************************
-#define  I2C2_CTRL                 0x190008    // I2C #2 control
-
-//*****************************************************************************
-#define  I2C2_RDATA                0x19000C    // I2C #2 read data
-
-//*****************************************************************************
-#define  I2C2_STAT                 0x190010    // I2C #2 status
-
-//*****************************************************************************
-// I2C #3
-//*****************************************************************************
-#define  I2C3_ADDR                 0x1A0000    // I2C #3 address
-
-//*****************************************************************************
-#define  I2C3_WDATA                0x1A0004    // I2C #3 write data
-
-//*****************************************************************************
-#define  I2C3_CTRL                 0x1A0008    // I2C #3 control
-
-//*****************************************************************************
-#define  I2C3_RDATA                0x1A000C    // I2C #3 read data
-
-//*****************************************************************************
-#define  I2C3_STAT                 0x1A0010    // I2C #3 status
-
-//*****************************************************************************
-// UART
-//*****************************************************************************
-#define  UART_CTL                  0x1B0000    // UART Control Register
-#define  FLD_LOOP_BACK_EN          (1 << 7)    // RW field - default 0
-#define  FLD_RX_TRG_SZ             (3 << 2)    // RW field - default 0
-#define  FLD_RX_EN                 (1 << 1)    // RW field - default 0
-#define  FLD_TX_EN                 (1 << 0)    // RW field - default 0
-
-//*****************************************************************************
-#define  UART_BRD                  0x1B0004    // UART Baud Rate Divisor
-#define  FLD_BRD                   0x0000FFFF  // RW field - default 0x197
-
-//*****************************************************************************
-#define  UART_DBUF                 0x1B0008    // UART Tx/Rx Data BuFFer
-#define  FLD_DB                    0xFFFFFFFF  // RW field - default 0
-
-//*****************************************************************************
-#define  UART_ISR                  0x1B000C    // UART Interrupt Status
-#define  FLD_RXD_TIMEOUT_EN        (1 << 7)    // RW field - default 0
-#define  FLD_FRM_ERR_EN            (1 << 6)    // RW field - default 0
-#define  FLD_RXD_RDY_EN            (1 << 5)    // RW field - default 0
-#define  FLD_TXD_EMPTY_EN          (1 << 4)    // RW field - default 0
-#define  FLD_RXD_OVERFLOW          (1 << 3)    // RW field - default 0
-#define  FLD_FRM_ERR               (1 << 2)    // RW field - default 0
-#define  FLD_RXD_RDY               (1 << 1)    // RW field - default 0
-#define  FLD_TXD_EMPTY             (1 << 0)    // RW field - default 0
-
-//*****************************************************************************
-#define  UART_CNT                  0x1B0010    // UART Tx/Rx FIFO Byte Count
-#define  FLD_TXD_CNT               (0x1F << 8) // RW field - default 0
-#define  FLD_RXD_CNT               (0x1F << 0) // RW field - default 0
-
-//*****************************************************************************
-// Motion Detection
+/* ***************************************************************************** */
+/* I2C #1 */
+/* ***************************************************************************** */
+#define  I2C1_ADDR                 0x180000    /* I2C #1 address */
+#define  FLD_I2C_DADDR             0xfe000000  /* RW [31:25] I2C Device Address */
+                                                /* RO [24] reserved */
+/* ***************************************************************************** */
+#define  FLD_I2C_SADDR             0x00FFFFFF  /* RW [23:0]  I2C Sub-address */
+
+/* ***************************************************************************** */
+#define  I2C1_WDATA                0x180004    /* I2C #1 write data */
+#define  FLD_I2C_WDATA             0xFFFFFFFF  /* RW [31:0] */
+
+/* ***************************************************************************** */
+#define  I2C1_CTRL                 0x180008    /* I2C #1 control */
+#define  FLD_I2C_PERIOD            0xFF000000  /* RW [31:24] */
+#define  FLD_I2C_SCL_IN            0x00200000  /* RW [21] */
+#define  FLD_I2C_SDA_IN            0x00100000  /* RW [20] */
+                                                /* RO [19:18] reserved */
+#define  FLD_I2C_SCL_OUT           0x00020000  /* RW [17] */
+#define  FLD_I2C_SDA_OUT           0x00010000  /* RW [16] */
+                                                /* RO [15] reserved */
+#define  FLD_I2C_DATA_LEN          0x00007000  /* RW [14:12] */
+#define  FLD_I2C_SADDR_INC         0x00000800  /* RW [11] */
+                                                /* RO [10:9] reserved */
+#define  FLD_I2C_SADDR_LEN         0x00000300  /* RW [9:8] */
+                                                /* RO [7:6] reserved */
+#define  FLD_I2C_SOFT              0x00000020  /* RW [5] */
+#define  FLD_I2C_NOSTOP            0x00000010  /* RW [4] */
+#define  FLD_I2C_EXTEND            0x00000008  /* RW [3] */
+#define  FLD_I2C_SYNC              0x00000004  /* RW [2] */
+#define  FLD_I2C_READ_SA           0x00000002  /* RW [1] */
+#define  FLD_I2C_READ_WRN          0x00000001  /* RW [0] */
+
+/* ***************************************************************************** */
+#define  I2C1_RDATA                0x18000C    /* I2C #1 read data */
+#define  FLD_I2C_RDATA             0xFFFFFFFF  /* RO [31:0] */
+
+/* ***************************************************************************** */
+#define  I2C1_STAT                 0x180010    /* I2C #1 status */
+#define  FLD_I2C_XFER_IN_PROG      0x00000002  /* RO [1] */
+#define  FLD_I2C_RACK              0x00000001  /* RO [0] */
+
+/* ***************************************************************************** */
+/* I2C #2 */
+/* ***************************************************************************** */
+#define  I2C2_ADDR                 0x190000    /* I2C #2 address */
+
+/* ***************************************************************************** */
+#define  I2C2_WDATA                0x190004    /* I2C #2 write data */
+
+/* ***************************************************************************** */
+#define  I2C2_CTRL                 0x190008    /* I2C #2 control */
+
+/* ***************************************************************************** */
+#define  I2C2_RDATA                0x19000C    /* I2C #2 read data */
+
+/* ***************************************************************************** */
+#define  I2C2_STAT                 0x190010    /* I2C #2 status */
+
+/* ***************************************************************************** */
+/* I2C #3 */
+/* ***************************************************************************** */
+#define  I2C3_ADDR                 0x1A0000    /* I2C #3 address */
+
+/* ***************************************************************************** */
+#define  I2C3_WDATA                0x1A0004    /* I2C #3 write data */
+
+/* ***************************************************************************** */
+#define  I2C3_CTRL                 0x1A0008    /* I2C #3 control */
+
+/* ***************************************************************************** */
+#define  I2C3_RDATA                0x1A000C    /* I2C #3 read data */
+
+/* ***************************************************************************** */
+#define  I2C3_STAT                 0x1A0010    /* I2C #3 status */
+
+/* ***************************************************************************** */
+/* UART */
+/* ***************************************************************************** */
+#define  UART_CTL                  0x1B0000    /* UART Control Register */
+#define  FLD_LOOP_BACK_EN          (1 << 7)    /* RW field - default 0 */
+#define  FLD_RX_TRG_SZ             (3 << 2)    /* RW field - default 0 */
+#define  FLD_RX_EN                 (1 << 1)    /* RW field - default 0 */
+#define  FLD_TX_EN                 (1 << 0)    /* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define  UART_BRD                  0x1B0004    /* UART Baud Rate Divisor */
+#define  FLD_BRD                   0x0000FFFF  /* RW field - default 0x197 */
+
+/* ***************************************************************************** */
+#define  UART_DBUF                 0x1B0008    /* UART Tx/Rx Data BuFFer */
+#define  FLD_DB                    0xFFFFFFFF  /* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define  UART_ISR                  0x1B000C    /* UART Interrupt Status */
+#define  FLD_RXD_TIMEOUT_EN        (1 << 7)    /* RW field - default 0 */
+#define  FLD_FRM_ERR_EN            (1 << 6)    /* RW field - default 0 */
+#define  FLD_RXD_RDY_EN            (1 << 5)    /* RW field - default 0 */
+#define  FLD_TXD_EMPTY_EN          (1 << 4)    /* RW field - default 0 */
+#define  FLD_RXD_OVERFLOW          (1 << 3)    /* RW field - default 0 */
+#define  FLD_FRM_ERR               (1 << 2)    /* RW field - default 0 */
+#define  FLD_RXD_RDY               (1 << 1)    /* RW field - default 0 */
+#define  FLD_TXD_EMPTY             (1 << 0)    /* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define  UART_CNT                  0x1B0010    /* UART Tx/Rx FIFO Byte Count */
+#define  FLD_TXD_CNT               (0x1F << 8) /* RW field - default 0 */
+#define  FLD_RXD_CNT               (0x1F << 0) /* RW field - default 0 */
+
+/* ***************************************************************************** */
+/* Motion Detection */
 #define  MD_CH0_GRID_BLOCK_YCNT    0x170014
 #define  MD_CH1_GRID_BLOCK_YCNT    0x170094
 #define  MD_CH2_GRID_BLOCK_YCNT    0x170114
 #define PIXEL_ENGINE_VIP1 0
 #define PIXEL_ENGINE_VIP2 1
 
-#endif //Athena_REGISTERS
+#endif /* Athena_REGISTERS */
index bd677ee229968d6d2a02b15daef2179ff26c0315..5f05d153bc4d5dc49d57fb800b5ab5511e5ce164 100644 (file)
 #ifndef __ATHENA_SRAM_H__
 #define __ATHENA_SRAM_H__
 
-//#define RX_SRAM_START_SIZE        = 0;  //  Start of reserved SRAM
-#define VID_CMDS_SIZE             80   //  Video CMDS size in bytes
-#define AUDIO_CMDS_SIZE           80   //  AUDIO CMDS size in bytes
-#define MBIF_CMDS_SIZE            80   //  MBIF  CMDS size in bytes
+/* #define RX_SRAM_START_SIZE        = 0;  //  Start of reserved SRAM */
+#define VID_CMDS_SIZE             80   /* Video CMDS size in bytes */
+#define AUDIO_CMDS_SIZE           80   /* AUDIO CMDS size in bytes */
+#define MBIF_CMDS_SIZE            80   /* MBIF  CMDS size in bytes */
 
-//#define RX_SRAM_POOL_START_SIZE   = 0;  //  Start of useable RX SRAM for buffers
-#define VID_IQ_SIZE               64   //  VID instruction queue size in bytes
+/* #define RX_SRAM_POOL_START_SIZE   = 0;  //  Start of useable RX SRAM for buffers */
+#define VID_IQ_SIZE               64   /* VID instruction queue size in bytes */
 #define MBIF_IQ_SIZE              64
-#define AUDIO_IQ_SIZE             64   //  AUD instruction queue size in bytes
+#define AUDIO_IQ_SIZE             64   /* AUD instruction queue size in bytes */
 
-#define VID_CDT_SIZE              64   //  VID cluster descriptor table size in bytes
-#define MBIF_CDT_SIZE             64   //  MBIF/HBI cluster descriptor table size in bytes
-#define AUDIO_CDT_SIZE            48   //  AUD cluster descriptor table size in bytes
+#define VID_CDT_SIZE              64   /* VID cluster descriptor table size in bytes */
+#define MBIF_CDT_SIZE             64   /* MBIF/HBI cluster descriptor table size in bytes */
+#define AUDIO_CDT_SIZE            48   /* AUD cluster descriptor table size in bytes */
 
-//#define RX_SRAM_POOL_FREE_SIZE    = 16; //  Start of available RX SRAM
-//#define RX_SRAM_END_SIZE          = 0;  //  End of RX SRAM
+/* #define RX_SRAM_POOL_FREE_SIZE    = 16; //  Start of available RX SRAM */
+/* #define RX_SRAM_END_SIZE          = 0;  //  End of RX SRAM */
 
-//#define TX_SRAM_POOL_START_SIZE   = 0;  //  Start of transmit pool SRAM
-//#define MSI_DATA_SIZE             = 64; //  Reserved (MSI Data, RISC working stora
+/* #define TX_SRAM_POOL_START_SIZE   = 0;  //  Start of transmit pool SRAM */
+/* #define MSI_DATA_SIZE             = 64; //  Reserved (MSI Data, RISC working stora */
 
-#define VID_CLUSTER_SIZE          1440 //  VID cluster data line
-#define AUDIO_CLUSTER_SIZE        128  //  AUDIO cluster data line
-#define MBIF_CLUSTER_SIZE         1440 //  MBIF/HBI cluster data line
+#define VID_CLUSTER_SIZE          1440 /* VID cluster data line */
+#define AUDIO_CLUSTER_SIZE        128  /* AUDIO cluster data line */
+#define MBIF_CLUSTER_SIZE         1440 /* MBIF/HBI cluster data line */
 
-//#define TX_SRAM_POOL_FREE_SIZE    = 704;    //  Start of available TX SRAM
-//#define TX_SRAM_END_SIZE          = 0;      //  End of TX SRAM
+/* #define TX_SRAM_POOL_FREE_SIZE    = 704;    //  Start of available TX SRAM */
+/* #define TX_SRAM_END_SIZE          = 0;      //  End of TX SRAM */
 
-// Receive SRAM
+/* Receive SRAM */
 #define RX_SRAM_START             0x10000
 #define VID_A_DOWN_CMDS           0x10000
 #define VID_B_DOWN_CMDS           0x10050
@@ -78,9 +78,9 @@
 #define AUD_E_UP_CMDS             0x10730
 #define MBIF_A_DOWN_CMDS          0x10780
 #define MBIF_B_DOWN_CMDS          0x107D0
-#define DMA_SCRATCH_PAD           0x10820      // Scratch pad area from 0x10820 to 0x10B40
+#define DMA_SCRATCH_PAD           0x10820      /* Scratch pad area from 0x10820 to 0x10B40 */
 
-//#define RX_SRAM_POOL_START        = 0x105B0;
+/* #define RX_SRAM_POOL_START        = 0x105B0; */
 
 #define VID_A_IQ                  0x11000
 #define VID_B_IQ                  0x11040
 #define MBIF_A_CDT                0x10C00
 #define MBIF_B_CDT                0x10CC0
 
-// Cluster Buffer for RX
+/* Cluster Buffer for RX */
 #define VID_A_UP_CLUSTER_1        0x11400
 #define VID_A_UP_CLUSTER_2        0x119A0
 #define VID_A_UP_CLUSTER_3        0x11F40
 #define RX_SRAM_POOL_FREE         0x1CE00
 #define RX_SRAM_END               0x1D000
 
-// Free Receive SRAM    144 Bytes
+/* Free Receive SRAM    144 Bytes */
 
-// Transmit SRAM
+/* Transmit SRAM */
 #define TX_SRAM_POOL_START        0x00000
 
 #define VID_A_DOWN_CLUSTER_1      0x00040
index 343df6619fe848f1d8726d76bca99e87e7d28d90..d12dbb572e8b913598e10ac92cd2c436618f3bfa 100644 (file)
@@ -84,7 +84,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
 {
        unsigned int line, i;
        struct sram_channel *sram_ch =
-           &dev->sram_channels[dev->_channel2_upstream_select];
+          dev->channels[dev->_channel2_upstream_select].sram_channels;
        int dist_betwn_starts = bpl * 2;
 
        /* sync instruction */
@@ -110,8 +110,11 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
                        offset += dist_betwn_starts;
                }
 
-               // check if we need to enable the FIFO after the first 4 lines
-               // For the upstream video channel, the risc engine will enable the FIFO.
+              /*
+                check if we need to enable the FIFO after the first 4 lines
+                 For the upstream video channel, the risc engine will enable
+                 the FIFO.
+              */
                if (fifo_enable && line == 3) {
                        *(rp++) = RISC_WRITECR;
                        *(rp++) = sram_ch->dma_ctl;
@@ -130,7 +133,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
 {
        __le32 *rp;
        int fifo_enable = 0;
-       int singlefield_lines = lines >> 1;     //get line count for single field
+       int singlefield_lines = lines >> 1; /*get line count for single field */
        int odd_num_lines = singlefield_lines;
        int frame = 0;
        int frame_size = 0;
@@ -174,7 +177,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
 
                fifo_enable = FIFO_DISABLE;
 
-               //Even field
+              /* Even field */
                rp = cx25821_risc_field_upstream_ch2(dev, rp,
                                                     dev->
                                                     _data_buf_phys_addr_ch2 +
@@ -192,7 +195,10 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
                        risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2;
                }
 
-               // Loop to 2ndFrameRISC or to Start of Risc program & generate IRQ
+              /*
+                 Loop to 2ndFrameRISC or to Start of
+                 Risc program & generate IRQ
+              */
                *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
                *(rp++) = cpu_to_le32(risc_phys_jump_addr);
                *(rp++) = cpu_to_le32(0);
@@ -204,7 +210,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
 void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
 {
        struct sram_channel *sram_ch =
-           &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_J];
+          dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
        u32 tmp = 0;
 
        if (!dev->_is_running_ch2) {
@@ -212,15 +218,15 @@ void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
                    ("cx25821: No video file is currently running so return!\n");
                return;
        }
-       //Disable RISC interrupts
+       /* Disable RISC interrupts */
        tmp = cx_read(sram_ch->int_msk);
        cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
 
-       //Turn OFF risc and fifo
+       /* Turn OFF risc and fifo */
        tmp = cx_read(sram_ch->dma_ctl);
        cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
 
-       //Clear data buffer memory
+       /* Clear data buffer memory */
        if (dev->_data_buf_virt_addr_ch2)
                memset(dev->_data_buf_virt_addr_ch2, 0,
                       dev->_data_buf_size_ch2);
@@ -371,8 +377,8 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
        }
 
        cx25821_get_frame_ch2(dev,
-                             &dev->sram_channels[dev->
-                                                 _channel2_upstream_select]);
+                            dev->channels[dev->
+                              _channel2_upstream_select].sram_channels);
 }
 
 int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
@@ -488,7 +494,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
                return -ENOMEM;
        }
 
-       //Iniitize at this address until n bytes to 0
+       /* Iniitize at this address until n bytes to 0 */
        memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2);
 
        if (dev->_data_buf_virt_addr_ch2 != NULL) {
@@ -496,7 +502,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
                                    dev->_data_buf_virt_addr_ch2,
                                    dev->_data_buf_phys_addr_ch2);
        }
-       //For Video Data buffer allocation
+       /* For Video Data buffer allocation */
        dev->_data_buf_virt_addr_ch2 =
            pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2,
                                 &data_dma_addr);
@@ -509,14 +515,14 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
                return -ENOMEM;
        }
 
-       //Initialize at this address until n bytes to 0
+       /* Initialize at this address until n bytes to 0 */
        memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2);
 
        ret = cx25821_openfile_ch2(dev, sram_ch);
        if (ret < 0)
                return ret;
 
-       //Creating RISC programs
+       /* Creating RISC programs */
        ret =
            cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
                                             dev->_lines_count_ch2);
@@ -536,7 +542,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
                                   u32 status)
 {
        u32 int_msk_tmp;
-       struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
        int singlefield_lines = NTSC_FIELD_HEIGHT;
        int line_size_in_bytes = Y422_LINE_SZ;
        int odd_risc_prog_size = 0;
@@ -544,10 +550,13 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
        __le32 *rp;
 
        if (status & FLD_VID_SRC_RISC1) {
-               // We should only process one program per call
+              /* We should only process one program per call */
                u32 prog_cnt = cx_read(channel->gpcnt);
 
-               //Since we've identified our IRQ, clear our bits from the interrupt mask and interrupt status registers
+              /*
+                 Since we've identified our IRQ, clear our bits from the
+                 interrupt mask and interrupt status registers
+              */
                int_msk_tmp = cx_read(channel->int_msk);
                cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
                cx_write(channel->int_stat, _intr_msk);
@@ -588,7 +597,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
                                                                    FIFO_DISABLE,
                                                                    ODD_FIELD);
 
-                               // Jump to Even Risc program of 1st Frame
+                              /* Jump to Even Risc program of 1st Frame */
                                *(rp++) = cpu_to_le32(RISC_JUMP);
                                *(rp++) = cpu_to_le32(risc_phys_jump_addr);
                                *(rp++) = cpu_to_le32(0);
@@ -603,7 +612,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
                       dev->_frame_count_ch2);
                return -1;
        }
-       //ElSE, set the interrupt mask register, re-enable irq.
+       /* ElSE, set the interrupt mask register, re-enable irq. */
        int_msk_tmp = cx_read(channel->int_msk);
        cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
 
@@ -623,12 +632,12 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
 
        channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
 
-       sram_ch = &dev->sram_channels[channel_num];
+       sram_ch = dev->channels[channel_num].sram_channels;
 
        msk_stat = cx_read(sram_ch->int_mstat);
        vid_status = cx_read(sram_ch->int_stat);
 
-       // Only deal with our interrupt
+       /* Only deal with our interrupt */
        if (vid_status) {
                handled =
                    cx25821_video_upstream_irq_ch2(dev, channel_num,
@@ -658,7 +667,10 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
        value |= dev->_isNTSC_ch2 ? 0 : 0x10;
        cx_write(ch->vid_fmt_ctl, value);
 
-       // set number of active pixels in each line. Default is 720 pixels in both NTSC and PAL format
+       /*
+         set number of active pixels in each line. Default is 720
+         pixels in both NTSC and PAL format
+       */
        cx_write(ch->vid_active_ctl1, width);
 
        num_lines = (height / 2) & 0x3FF;
@@ -670,7 +682,7 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
 
        value = (num_lines << 16) | odd_num_lines;
 
-       // set number of active lines in field 0 (top) and field 1 (bottom)
+       /* set number of active lines in field 0 (top) and field 1 (bottom) */
        cx_write(ch->vid_active_ctl2, value);
 
        cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
@@ -682,21 +694,27 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
        u32 tmp = 0;
        int err = 0;
 
-       // 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+       /*
+         656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
+         for channel A-C
+       */
        tmp = cx_read(VID_CH_MODE_SEL);
        cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
 
-       // Set the physical start address of the RISC program in the initial program counter(IPC) member of the cmds.
+       /*
+         Set the physical start address of the RISC program in the initial
+         program counter(IPC) member of the cmds.
+       */
        cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2);
-       cx_write(sram_ch->cmds_start + 4, 0);   /* Risc IPC High 64 bits 63-32 */
+       cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
 
        /* reset counter */
        cx_write(sram_ch->gpcnt_ctl, 3);
 
-       // Clear our bits from the interrupt status register.
+       /* Clear our bits from the interrupt status register. */
        cx_write(sram_ch->int_stat, _intr_msk);
 
-       //Set the interrupt mask register, enable irq.
+       /* Set the interrupt mask register, enable irq. */
        cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
        tmp = cx_read(sram_ch->int_msk);
        cx_write(sram_ch->int_msk, tmp |= _intr_msk);
@@ -709,7 +727,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
                       dev->pci->irq);
                goto fail_irq;
        }
-       // Start the DMA  engine
+       /* Start the DMA  engine */
        tmp = cx_read(sram_ch->dma_ctl);
        cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
 
@@ -740,7 +758,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
        }
 
        dev->_channel2_upstream_select = channel_select;
-       sram_ch = &dev->sram_channels[channel_select];
+       sram_ch = dev->channels[channel_select].sram_channels;
 
        INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
        dev->_irq_queues_ch2 =
@@ -751,7 +769,10 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
                    ("cx25821: create_singlethread_workqueue() for Video FAILED!\n");
                return -ENOMEM;
        }
-       // 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+       /*
+         656/VIP SRC Upstream Channel I & J and 7 -
+         Host Bus Interface for channel A-C
+       */
        tmp = cx_read(VID_CH_MODE_SEL);
        cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
 
@@ -787,7 +808,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
                       str_length + 1);
        }
 
-       //Default if filename is empty string
+       /* Default if filename is empty string */
        if (strcmp(dev->input_filename_ch2, "") == 0) {
                if (dev->_isNTSC_ch2) {
                        dev->_filename_ch2 =
@@ -812,7 +833,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
        dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2;
        dev->upstream_databuf_size_ch2 = data_frame_size * 2;
 
-       //Allocating buffers and prepare RISC program
+       /* Allocating buffers and prepare RISC program */
        retval =
            cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
                                                dev->_line_size_ch2);
index 73feea114c1cb5691f763eb9b8aa261e10803726..62340636c91609174cc0144fe157cd5d75bd5d31 100644 (file)
@@ -37,7 +37,7 @@
 #define RESET_STATUS          -1
 #define NUM_NO_OPS            5
 
-// PAL and NTSC line sizes and number of lines.
+/* PAL and NTSC line sizes and number of lines. */
 #define WIDTH_D1              720
 #define NTSC_LINES_PER_FRAME  480
 #define PAL_LINES_PER_FRAME   576
index 7a3dad91eba8f423c5663f7a618df452188101cf..756a820a76cb2a1386b1b8629d854c75aac078a3 100644 (file)
@@ -134,7 +134,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
 {
        unsigned int line, i;
        struct sram_channel *sram_ch =
-           &dev->sram_channels[dev->_channel_upstream_select];
+          dev->channels[dev->_channel_upstream_select].sram_channels;
        int dist_betwn_starts = bpl * 2;
 
        /* sync instruction */
@@ -253,7 +253,7 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
 void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
 {
        struct sram_channel *sram_ch =
-           &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_I];
+          dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
        u32 tmp = 0;
 
        if (!dev->_is_running) {
@@ -346,20 +346,23 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
        if (IS_ERR(myfile)) {
                const int open_errno = -PTR_ERR(myfile);
-               printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
-                      __func__, dev->_filename, open_errno);
+              printk(KERN_ERR
+                  "%s(): ERROR opening file(%s) with errno = %d!\n",
+                  __func__, dev->_filename, open_errno);
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
-                       printk(KERN_ERR "%s: File has no file operations registered!",
-                              __func__);
+                      printk(KERN_ERR
+                          "%s: File has no file operations registered!",
+                          __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
 
                if (!myfile->f_op->read) {
-                       printk(KERN_ERR "%s: File has no READ operations registered!",
-                              __func__);
+                      printk(KERN_ERR
+                          "%s: File has no READ operations registered!",
+                          __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
@@ -386,7 +389,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
                        if (vfs_read_retval < line_size) {
                                printk(KERN_INFO
-                                      "Done: exit %s() since no more bytes to read from Video file.\n",
+                                     "Done: exit %s() since no more bytes to \
+                                     read from Video file.\n",
                                       __func__);
                                break;
                        }
@@ -411,13 +415,15 @@ static void cx25821_vidups_handler(struct work_struct *work)
            container_of(work, struct cx25821_dev, _irq_work_entry);
 
        if (!dev) {
-               printk(KERN_ERR "ERROR %s(): since container_of(work_struct) FAILED!\n",
-                      __func__);
+              printk(KERN_ERR
+                  "ERROR %s(): since container_of(work_struct) FAILED!\n",
+                  __func__);
                return;
        }
 
        cx25821_get_frame(dev,
-                         &dev->sram_channels[dev->_channel_upstream_select]);
+                        dev->channels[dev->_channel_upstream_select].
+                                              sram_channels);
 }
 
 int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
@@ -437,20 +443,22 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
        if (IS_ERR(myfile)) {
                const int open_errno = -PTR_ERR(myfile);
-               printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
+              printk(KERN_ERR  "%s(): ERROR opening file(%s) with errno = %d!\n",
                       __func__, dev->_filename, open_errno);
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
-                       printk(KERN_ERR "%s: File has no file operations registered!",
-                              __func__);
+                      printk(KERN_ERR
+                          "%s: File has no file operations registered!",
+                          __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
 
                if (!myfile->f_op->read) {
-                       printk
-                           (KERN_ERR "%s: File has no READ operations registered!  Returning.",
+                      printk(KERN_ERR
+                          "%s: File has no READ operations registered!  \
+                          Returning.",
                             __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
@@ -480,7 +488,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
                                if (vfs_read_retval < line_size) {
                                        printk(KERN_INFO
-                                              "Done: exit %s() since no more bytes to read from Video file.\n",
+                                           "Done: exit %s() since no more \
+                                           bytes to read from Video file.\n",
                                               __func__);
                                        break;
                                }
@@ -526,7 +535,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
 
        if (!dev->_dma_virt_addr) {
                printk
-                   (KERN_ERR "cx25821: FAILED to allocate memory for Risc buffer! Returning.\n");
+                  (KERN_ERR "cx25821: FAILED to allocate memory for Risc \
+                  buffer! Returning.\n");
                return -ENOMEM;
        }
 
@@ -547,7 +557,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
 
        if (!dev->_data_buf_virt_addr) {
                printk
-                   (KERN_ERR "cx25821: FAILED to allocate memory for data buffer! Returning.\n");
+                  (KERN_ERR "cx25821: FAILED to allocate memory for data \
+                  buffer! Returning.\n");
                return -ENOMEM;
        }
 
@@ -578,7 +589,7 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
                               u32 status)
 {
        u32 int_msk_tmp;
-       struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
        int singlefield_lines = NTSC_FIELD_HEIGHT;
        int line_size_in_bytes = Y422_LINE_SZ;
        int odd_risc_prog_size = 0;
@@ -642,16 +653,16 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
        } else {
                if (status & FLD_VID_SRC_UF)
                        printk
-                           (KERN_ERR "%s: Video Received Underflow Error Interrupt!\n",
-                            __func__);
+                          (KERN_ERR "%s: Video Received Underflow Error \
+                          Interrupt!\n", __func__);
 
                if (status & FLD_VID_SRC_SYNC)
-                       printk(KERN_ERR "%s: Video Received Sync Error Interrupt!\n",
-                              __func__);
+                      printk(KERN_ERR "%s: Video Received Sync Error \
+                      Interrupt!\n", __func__);
 
                if (status & FLD_VID_SRC_OPC_ERR)
-                       printk(KERN_ERR "%s: Video Received OpCode Error Interrupt!\n",
-                              __func__);
+                      printk(KERN_ERR "%s: Video Received OpCode Error \
+                      Interrupt!\n", __func__);
        }
 
        if (dev->_file_status == END_OF_FILE) {
@@ -679,7 +690,7 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
 
        channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
 
-       sram_ch = &dev->sram_channels[channel_num];
+       sram_ch = dev->channels[channel_num].sram_channels;
 
        msk_stat = cx_read(sram_ch->int_mstat);
        vid_status = cx_read(sram_ch->int_stat);
@@ -800,14 +811,15 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
        }
 
        dev->_channel_upstream_select = channel_select;
-       sram_ch = &dev->sram_channels[channel_select];
+       sram_ch = dev->channels[channel_select].sram_channels;
 
        INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler);
        dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
 
        if (!dev->_irq_queues) {
                printk
-                   (KERN_ERR "cx25821: create_singlethread_workqueue() for Video FAILED!\n");
+                  (KERN_ERR "cx25821: create_singlethread_workqueue() for \
+                  Video FAILED!\n");
                return -ENOMEM;
        }
        /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
index cc9f9384251468591204625d8271c71fb509a0f6..10dee5c24a818b0547dc1097fb78efe35fe2d72f 100644 (file)
@@ -38,7 +38,7 @@
 #define RESET_STATUS          -1
 #define NUM_NO_OPS            5
 
-// PAL and NTSC line sizes and number of lines.
+/* PAL and NTSC line sizes and number of lines. */
 #define WIDTH_D1              720
 #define NTSC_LINES_PER_FRAME  480
 #define PAL_LINES_PER_FRAME   576
index 791212c1a661d65e25a13cf2b3a63dd24b86e7af..1d5e8796d383ba4ab90767c4fb4f59d9541da1e6 100644 (file)
@@ -4,6 +4,9 @@
  *  Copyright (C) 2009 Conexant Systems Inc.
  *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
  *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *  Parts adapted/taken from Eduardo Moscoso Rubino
+ *  Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.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
@@ -24,7 +27,7 @@
 #include "cx25821-video.h"
 
 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
 MODULE_LICENSE("GPL");
 
 static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
@@ -48,7 +51,10 @@ unsigned int vid_limit = 16;
 module_param(vid_limit, int, 0644);
 MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 
-static void init_controls(struct cx25821_dev *dev, int chan_num);
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num);
+
+static const struct v4l2_file_operations video_fops;
+static const struct v4l2_ioctl_ops video_ioctl_ops;
 
 #define FORMAT_FLAGS_PACKED       0x01
 
@@ -211,7 +217,7 @@ static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
 }
 */
 
-// resource management
+/* resource management */
 int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit)
 {
        dprintk(1, "%s()\n", __func__);
@@ -221,14 +227,14 @@ int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int
 
        /* is it free? */
        mutex_lock(&dev->lock);
-       if (dev->resources & bit) {
+       if (dev->channels[fh->channel_id].resources & bit) {
                /* no, someone else uses it */
                mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources |= bit;
-       dev->resources |= bit;
+       dev->channels[fh->channel_id].resources |= bit;
        dprintk(1, "res: get %d\n", bit);
        mutex_unlock(&dev->lock);
        return 1;
@@ -239,9 +245,9 @@ int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
        return fh->resources & bit;
 }
 
-int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit)
+int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
 {
-       return dev->resources & bit;
+       return fh->dev->channels[fh->channel_id].resources & bit;
 }
 
 void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits)
@@ -251,7 +257,7 @@ void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned i
 
        mutex_lock(&dev->lock);
        fh->resources &= ~bits;
-       dev->resources &= ~bits;
+       dev->channels[fh->channel_id].resources &= ~bits;
        dprintk(1, "res: put %d\n", bits);
        mutex_unlock(&dev->lock);
 }
@@ -358,11 +364,11 @@ void cx25821_vid_timeout(unsigned long data)
        struct cx25821_data *timeout_data = (struct cx25821_data *)data;
        struct cx25821_dev *dev = timeout_data->dev;
        struct sram_channel *channel = timeout_data->channel;
-       struct cx25821_dmaqueue *q = &dev->vidq[channel->i];
+       struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq;
        struct cx25821_buffer *buf;
        unsigned long flags;
 
-       //cx25821_sram_channel_dump(dev, channel);
+       /* cx25821_sram_channel_dump(dev, channel); */
        cx_clear(channel->dma_ctl, 0x11);
 
        spin_lock_irqsave(&dev->slock, flags);
@@ -384,7 +390,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
        u32 count = 0;
        int handled = 0;
        u32 mask;
-       struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
 
        mask = cx_read(channel->int_msk);
        if (0 == (status & mask))
@@ -404,7 +410,8 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
        if (status & FLD_VID_DST_RISC1) {
                spin_lock(&dev->slock);
                count = cx_read(channel->gpcnt);
-               cx25821_video_wakeup(dev, &dev->vidq[channel->i], count);
+              cx25821_video_wakeup(dev,
+                      &dev->channels[channel->i].vidq, count);
                spin_unlock(&dev->slock);
                handled++;
        }
@@ -413,8 +420,9 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
        if (status & 0x10) {
                dprintk(2, "stopper video\n");
                spin_lock(&dev->slock);
-               cx25821_restart_video_queue(dev, &dev->vidq[channel->i],
-                                           channel);
+              cx25821_restart_video_queue(dev,
+                              &dev->channels[channel->i].vidq,
+                                      channel);
                spin_unlock(&dev->slock);
                handled++;
        }
@@ -437,72 +445,95 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
 {
        cx_clear(PCI_INT_MSK, 1);
 
-       if (dev->video_dev[chan_num]) {
-               if (video_is_registered(dev->video_dev[chan_num]))
-                       video_unregister_device(dev->video_dev[chan_num]);
+       if (dev->channels[chan_num].video_dev) {
+              if (video_is_registered(dev->channels[chan_num].video_dev))
+                      video_unregister_device(
+                              dev->channels[chan_num].video_dev);
                else
-                       video_device_release(dev->video_dev[chan_num]);
+                      video_device_release(
+                              dev->channels[chan_num].video_dev);
 
-               dev->video_dev[chan_num] = NULL;
+              dev->channels[chan_num].video_dev = NULL;
 
-               btcx_riscmem_free(dev->pci, &dev->vidq[chan_num].stopper);
+              btcx_riscmem_free(dev->pci,
+                      &dev->channels[chan_num].vidq.stopper);
 
                printk(KERN_WARNING "device %d released!\n", chan_num);
        }
 
 }
 
-int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
-                          struct video_device *video_template)
+int cx25821_video_register(struct cx25821_dev *dev)
 {
        int err;
+       int i;
+
+       struct video_device cx25821_video_device = {
+              .name = "cx25821-video",
+              .fops = &video_fops,
+              .minor = -1,
+              .ioctl_ops = &video_ioctl_ops,
+              .tvnorms = CX25821_NORMS,
+              .current_norm = V4L2_STD_NTSC_M,
+       };
 
        spin_lock_init(&dev->slock);
 
-       //printk(KERN_WARNING "Channel %d\n", chan_num);
+    for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+              cx25821_init_controls(dev, i);
 
-#ifdef TUNER_FLAG
-       dev->tvnorm = video_template->current_norm;
-#endif
+              cx25821_risc_stopper(dev->pci,
+                              &dev->channels[i].vidq.stopper,
+                              dev->channels[i].sram_channels->dma_ctl,
+                              0x11, 0);
+
+              dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+              dev->channels[i].video_dev = NULL;
+              dev->channels[i].resources = 0;
+
+              cx_write(dev->channels[i].sram_channels->int_stat,
+                              0xffffffff);
+
+              INIT_LIST_HEAD(&dev->channels[i].vidq.active);
+              INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
+
+              dev->channels[i].timeout_data.dev = dev;
+              dev->channels[i].timeout_data.channel =
+                                      &cx25821_sram_channels[i];
+              dev->channels[i].vidq.timeout.function =
+                                      cx25821_vid_timeout;
+              dev->channels[i].vidq.timeout.data =
+                      (unsigned long)&dev->channels[i].timeout_data;
+              init_timer(&dev->channels[i].vidq.timeout);
+
+              /* register v4l devices */
+              dev->channels[i].video_dev = cx25821_vdev_init(dev,
+                      dev->pci, &cx25821_video_device, "video");
+
+              err = video_register_device(dev->channels[i].video_dev,
+                              VFL_TYPE_GRABBER, video_nr[dev->nr]);
+
+              if (err < 0)
+                      goto fail_unreg;
 
-       /* init video dma queues */
-       dev->timeout_data[chan_num].dev = dev;
-       dev->timeout_data[chan_num].channel = &dev->sram_channels[chan_num];
-       INIT_LIST_HEAD(&dev->vidq[chan_num].active);
-       INIT_LIST_HEAD(&dev->vidq[chan_num].queued);
-       dev->vidq[chan_num].timeout.function = cx25821_vid_timeout;
-       dev->vidq[chan_num].timeout.data =
-           (unsigned long)&dev->timeout_data[chan_num];
-       init_timer(&dev->vidq[chan_num].timeout);
-       cx25821_risc_stopper(dev->pci, &dev->vidq[chan_num].stopper,
-                            dev->sram_channels[chan_num].dma_ctl, 0x11, 0);
-
-       /* register v4l devices */
-       dev->video_dev[chan_num] =
-           cx25821_vdev_init(dev, dev->pci, video_template, "video");
-       err =
-           video_register_device(dev->video_dev[chan_num], VFL_TYPE_GRABBER,
-                                 video_nr[dev->nr]);
-
-       if (err < 0) {
-               goto fail_unreg;
        }
-       //set PCI interrupt
+
+    /* set PCI interrupt */
        cx_set(PCI_INT_MSK, 0xff);
 
        /* initial device configuration */
        mutex_lock(&dev->lock);
 #ifdef TUNER_FLAG
+       dev->tvnorm = cx25821_video_device.current_norm;
        cx25821_set_tvnorm(dev, dev->tvnorm);
 #endif
        mutex_unlock(&dev->lock);
 
-       init_controls(dev, chan_num);
 
-       return 0;
+    return 0;
 
-      fail_unreg:
-       cx25821_video_unregister(dev, chan_num);
+fail_unreg:
+       cx25821_video_unregister(dev, i);
        return err;
 }
 
@@ -533,7 +564,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        u32 line0_offset, line1_offset;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int bpl_local = LINE_SIZE_D1;
-       int channel_opened = 0;
+       int channel_opened = fh->channel_id;
 
        BUG_ON(NULL == fh->fmt);
        if (fh->width < 48 || fh->width > 720 ||
@@ -572,26 +603,29 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                channel_opened = (channel_opened < 0
                                  || channel_opened > 7) ? 7 : channel_opened;
 
-               if (dev->pixel_formats[channel_opened] == PIXEL_FRMT_411)
+              if (dev->channels[channel_opened]
+                      .pixel_formats == PIXEL_FRMT_411)
                        buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
                else
                        buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
 
-               if (dev->pixel_formats[channel_opened] == PIXEL_FRMT_411) {
+              if (dev->channels[channel_opened]
+                      .pixel_formats == PIXEL_FRMT_411) {
                        bpl_local = buf->bpl;
                } else {
-                       bpl_local = buf->bpl;   //Default
+                      bpl_local = buf->bpl;   /* Default */
 
                        if (channel_opened >= 0 && channel_opened <= 7) {
-                               if (dev->use_cif_resolution[channel_opened]) {
+                              if (dev->channels[channel_opened]
+                                              .use_cif_resolution) {
                                        if (dev->tvnorm & V4L2_STD_PAL_BG
                                            || dev->tvnorm & V4L2_STD_PAL_DK)
                                                bpl_local = 352 << 1;
                                        else
                                                bpl_local =
-                                                   dev->
-                                                   cif_width[channel_opened] <<
-                                                   1;
+                                                dev->channels[channel_opened].
+                                                cif_width <<
+                                                1;
                                }
                        }
                }
@@ -685,6 +719,383 @@ int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
        return videobuf_mmap_mapper(get_queue(fh), vma);
 }
 
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct cx25821_buffer *buf =
+          container_of(vb, struct cx25821_buffer, vb);
+       struct cx25821_buffer *prev;
+       struct cx25821_fh *fh = vq->priv_data;
+       struct cx25821_dev *dev = fh->dev;
+       struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
+
+       /* add jump to stopper */
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
+
+       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
+
+       if (!list_empty(&q->queued)) {
+              list_add_tail(&buf->vb.queue, &q->queued);
+              buf->vb.state = VIDEOBUF_QUEUED;
+              dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
+                      buf->vb.i);
+
+       } else if (list_empty(&q->active)) {
+              list_add_tail(&buf->vb.queue, &q->active);
+              cx25821_start_video_dma(dev, q, buf,
+                                      dev->channels[fh->channel_id].
+                                      sram_channels);
+              buf->vb.state = VIDEOBUF_ACTIVE;
+              buf->count = q->count++;
+              mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+              dprintk(2,
+                      "[%p/%d] buffer_queue - first active, buf cnt = %d, \
+                      q->count = %d\n",
+                      buf, buf->vb.i, buf->count, q->count);
+       } else {
+              prev =
+                  list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
+              if (prev->vb.width == buf->vb.width
+                  && prev->vb.height == buf->vb.height
+                  && prev->fmt == buf->fmt) {
+                      list_add_tail(&buf->vb.queue, &q->active);
+                      buf->vb.state = VIDEOBUF_ACTIVE;
+                      buf->count = q->count++;
+                      prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+                      /* 64 bit bits 63-32 */
+                      prev->risc.jmp[2] = cpu_to_le32(0);
+                      dprintk(2,
+                              "[%p/%d] buffer_queue - append to active, \
+                              buf->count=%d\n",
+                              buf, buf->vb.i, buf->count);
+
+              } else {
+                      list_add_tail(&buf->vb.queue, &q->queued);
+                      buf->vb.state = VIDEOBUF_QUEUED;
+                      dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
+                              buf->vb.i);
+              }
+       }
+
+       if (list_empty(&q->active))
+              dprintk(2, "active queue empty!\n");
+}
+
+static struct videobuf_queue_ops cx25821_video_qops = {
+       .buf_setup = cx25821_buffer_setup,
+       .buf_prepare = cx25821_buffer_prepare,
+       .buf_queue = buffer_queue,
+       .buf_release = cx25821_buffer_release,
+};
+
+static int video_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct cx25821_dev *h, *dev = video_drvdata(file);
+       struct cx25821_fh *fh;
+       struct list_head *list;
+       int minor = video_devdata(file)->minor;
+       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       u32 pix_format;
+       int ch_id = 0;
+       int i;
+
+       dprintk(1, "open dev=%s type=%s\n",
+                      video_device_node_name(vdev),
+                      v4l2_type_names[type]);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+              return -ENOMEM;
+
+       lock_kernel();
+
+       list_for_each(list, &cx25821_devlist)
+       {
+              h = list_entry(list, struct cx25821_dev, devlist);
+
+              for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
+                      if (h->channels[i].video_dev &&
+                          h->channels[i].video_dev->minor == minor) {
+                              dev = h;
+                              ch_id = i;
+                              type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                      }
+              }
+       }
+
+       if (NULL == dev) {
+              unlock_kernel();
+              return -ENODEV;
+       }
+
+       file->private_data = fh;
+       fh->dev = dev;
+       fh->type = type;
+       fh->width = 720;
+    fh->channel_id = ch_id;
+
+       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
+              fh->height = 576;
+       else
+              fh->height = 480;
+
+       dev->channel_opened = fh->channel_id;
+       pix_format =
+          (dev->channels[ch_id].pixel_formats ==
+           PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
+       fh->fmt = format_by_fourcc(pix_format);
+
+       v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
+
+       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
+                             &dev->pci->dev, &dev->slock,
+                             V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                             V4L2_FIELD_INTERLACED,
+                             sizeof(struct cx25821_buffer), fh);
+
+       dprintk(1, "post videobuf_queue_init()\n");
+       unlock_kernel();
+
+       return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user * data, size_t count,
+                        loff_t *ppos)
+{
+       struct cx25821_fh *fh = file->private_data;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+              if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
+                      return -EBUSY;
+
+              return videobuf_read_one(&fh->vidq, data, count, ppos,
+                                       file->f_flags & O_NONBLOCK);
+
+       default:
+              BUG();
+              return 0;
+       }
+}
+
+static unsigned int video_poll(struct file *file,
+                             struct poll_table_struct *wait)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_buffer *buf;
+
+       if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+              /* streaming capture */
+              if (list_empty(&fh->vidq.stream))
+                      return POLLERR;
+              buf = list_entry(fh->vidq.stream.next,
+                               struct cx25821_buffer, vb.stream);
+       } else {
+              /* read() capture */
+              buf = (struct cx25821_buffer *)fh->vidq.read_buf;
+              if (NULL == buf)
+                      return POLLERR;
+       }
+
+       poll_wait(file, &buf->vb.done, wait);
+       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
+              if (buf->vb.state == VIDEOBUF_DONE) {
+                      struct cx25821_dev *dev = fh->dev;
+
+                      if (dev && dev->channels[fh->channel_id]
+                                              .use_cif_resolution) {
+                              u8 cam_id = *((char *)buf->vb.baddr + 3);
+                              memcpy((char *)buf->vb.baddr,
+                                     (char *)buf->vb.baddr + (fh->width * 2),
+                                     (fh->width * 2));
+                              *((char *)buf->vb.baddr + 3) = cam_id;
+                      }
+              }
+
+              return POLLIN | POLLRDNORM;
+       }
+
+       return 0;
+}
+
+static int video_release(struct file *file)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+
+       /* stop the risc engine and fifo */
+       cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
+
+       /* stop video capture */
+       if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+              videobuf_queue_cancel(&fh->vidq);
+              cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
+       }
+
+       if (fh->vidq.read_buf) {
+              cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
+              kfree(fh->vidq.read_buf);
+       }
+
+       videobuf_mmap_free(&fh->vidq);
+
+       v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
+       file->private_data = NULL;
+       kfree(fh);
+
+       return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = fh->dev;
+
+       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+              return -EINVAL;
+
+       if (unlikely(i != fh->type))
+              return -EINVAL;
+
+       if (unlikely(!cx25821_res_get(dev, fh,
+                      cx25821_get_resource(fh, RESOURCE_VIDEO0))))
+              return -EBUSY;
+
+       return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = fh->dev;
+       int err, res;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+              return -EINVAL;
+       if (i != fh->type)
+              return -EINVAL;
+
+       res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
+       err = videobuf_streamoff(get_queue(fh));
+       if (err < 0)
+              return err;
+       cx25821_res_free(dev, fh, res);
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                              struct v4l2_format *f)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       int err;
+       int pix_format = PIXEL_FRMT_422;
+
+       if (fh) {
+              err = v4l2_prio_check(&dev->channels[fh->channel_id]
+                                              .prio, fh->prio);
+              if (0 != err)
+                      return err;
+       }
+
+       dprintk(2, "%s()\n", __func__);
+       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
+
+       if (0 != err)
+              return err;
+
+       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->vidq.field = f->fmt.pix.field;
+
+       /* check if width and height is valid based on set standard */
+       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
+              fh->width = f->fmt.pix.width;
+
+       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
+              fh->height = f->fmt.pix.height;
+
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
+              pix_format = PIXEL_FRMT_411;
+       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+              pix_format = PIXEL_FRMT_422;
+       else
+              return -EINVAL;
+
+       cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
+
+       /* check if cif resolution */
+       if (fh->width == 320 || fh->width == 352)
+              dev->channels[fh->channel_id].use_cif_resolution = 1;
+       else
+              dev->channels[fh->channel_id].use_cif_resolution = 0;
+
+       dev->channels[fh->channel_id].cif_width = fh->width;
+       medusa_set_resolution(dev, fh->width, SRAM_CH00);
+
+       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
+              fh->height, fh->vidq.field);
+       cx25821_call_all(dev, video, s_fmt, f);
+
+       return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       int ret_val = 0;
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
+
+    p->sequence = dev->channels[fh->channel_id].vidq.count;
+
+       return ret_val;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       struct cx25821_fh *fh = priv;
+       char name[32 + 2];
+
+       struct sram_channel *sram_ch = dev->channels[fh->channel_id]
+                                                      .sram_channels;
+       u32 tmp = 0;
+
+       snprintf(name, sizeof(name), "%s/2", dev->name);
+       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
+             dev->name);
+       cx25821_call_all(dev, core, log_status);
+       tmp = cx_read(sram_ch->dma_ctl);
+       printk(KERN_INFO "Video input 0 is %s\n",
+             (tmp & 0x11) ? "streaming" : "stopped");
+       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
+             dev->name);
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                       struct v4l2_control *ctl)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       int err;
+
+       if (fh) {
+              err = v4l2_prio_check(&dev->channels[fh->channel_id]
+                                              .prio, fh->prio);
+              if (0 != err)
+                      return err;
+       }
+
+       return cx25821_set_control(dev, ctl, fh->channel_id);
+}
+
 /* VIDEO IOCTLS                                                       */
 int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
 {
@@ -822,8 +1233,9 @@ int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
 {
        struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
+       struct cx25821_fh *fh = f;
 
-       *p = v4l2_prio_max(&dev->prio);
+       *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
 
        return 0;
 }
@@ -833,7 +1245,8 @@ int cx25821_vidioc_s_priority(struct file *file, void *f, enum v4l2_priority pri
        struct cx25821_fh *fh = f;
        struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
 
-       return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+       return v4l2_prio_change(&dev->channels[fh->channel_id]
+                                      .prio, &fh->prio, prio);
 }
 
 #ifdef TUNER_FLAG
@@ -846,7 +1259,8 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms)
        dprintk(1, "%s()\n", __func__);
 
        if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
+              err = v4l2_prio_check(&dev->channels[fh->channel_id]
+                                              .prio, fh->prio);
                if (0 != err)
                        return err;
        }
@@ -916,7 +1330,8 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
        dprintk(1, "%s(%d)\n", __func__, i);
 
        if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
+              err = v4l2_prio_check(&dev->channels[fh->channel_id]
+                                              .prio, fh->prio);
                if (0 != err)
                        return err;
        }
@@ -967,9 +1382,14 @@ int cx25821_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_freque
        int err;
 
        if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
+              dev = fh->dev;
+              err = v4l2_prio_check(&dev->channels[fh->channel_id]
+                                              .prio, fh->prio);
                if (0 != err)
                        return err;
+       } else {
+              printk(KERN_ERR "Invalid fh pointer!\n");
+              return -EINVAL;
        }
 
        return cx25821_set_freq(dev, f);
@@ -1031,7 +1451,8 @@ int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        int err;
 
        if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
+              err = v4l2_prio_check(&dev->channels[fh->channel_id]
+                                              .prio, fh->prio);
                if (0 != err)
                        return err;
        }
@@ -1046,7 +1467,7 @@ int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
 }
 
 #endif
-// ******************************************************************************************
+/*****************************************************************************/
 static const struct v4l2_queryctrl no_ctl = {
        .name = "42",
        .flags = V4L2_CTRL_FLAG_DISABLED,
@@ -1129,6 +1550,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
 int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl)
 {
        struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       struct cx25821_fh *fh = priv;
 
        const struct v4l2_queryctrl *ctrl;
 
@@ -1138,16 +1560,16 @@ int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ct
                return -EINVAL;
        switch (ctl->id) {
        case V4L2_CID_BRIGHTNESS:
-               ctl->value = dev->ctl_bright;
+              ctl->value = dev->channels[fh->channel_id].ctl_bright;
                break;
        case V4L2_CID_HUE:
-               ctl->value = dev->ctl_hue;
+              ctl->value = dev->channels[fh->channel_id].ctl_hue;
                break;
        case V4L2_CID_CONTRAST:
-               ctl->value = dev->ctl_contrast;
+              ctl->value = dev->channels[fh->channel_id].ctl_contrast;
                break;
        case V4L2_CID_SATURATION:
-               ctl->value = dev->ctl_saturation;
+              ctl->value = dev->channels[fh->channel_id].ctl_saturation;
                break;
        }
        return 0;
@@ -1181,19 +1603,19 @@ int cx25821_set_control(struct cx25821_dev *dev,
 
        switch (ctl->id) {
        case V4L2_CID_BRIGHTNESS:
-               dev->ctl_bright = ctl->value;
+              dev->channels[chan_num].ctl_bright = ctl->value;
                medusa_set_brightness(dev, ctl->value, chan_num);
                break;
        case V4L2_CID_HUE:
-               dev->ctl_hue = ctl->value;
+              dev->channels[chan_num].ctl_hue = ctl->value;
                medusa_set_hue(dev, ctl->value, chan_num);
                break;
        case V4L2_CID_CONTRAST:
-               dev->ctl_contrast = ctl->value;
+              dev->channels[chan_num].ctl_contrast = ctl->value;
                medusa_set_contrast(dev, ctl->value, chan_num);
                break;
        case V4L2_CID_SATURATION:
-               dev->ctl_saturation = ctl->value;
+              dev->channels[chan_num].ctl_saturation = ctl->value;
                medusa_set_saturation(dev, ctl->value, chan_num);
                break;
        }
@@ -1203,7 +1625,7 @@ int cx25821_set_control(struct cx25821_dev *dev,
        return err;
 }
 
-static void init_controls(struct cx25821_dev *dev, int chan_num)
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num)
 {
        struct v4l2_control ctrl;
        int i;
@@ -1239,23 +1661,24 @@ int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
        int err;
 
        if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
+              err = v4l2_prio_check(&dev->channels[fh->channel_id].
+                                              prio, fh->prio);
                if (0 != err)
                        return err;
        }
-       // cx25821_vidioc_s_crop not supported
+       /* cx25821_vidioc_s_crop not supported */
        return -EINVAL;
 }
 
 int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
 {
-       // cx25821_vidioc_g_crop not supported
+       /* cx25821_vidioc_g_crop not supported */
        return -EINVAL;
 }
 
 int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
 {
-       // medusa does not support video standard sensing of current input
+       /* medusa does not support video standard sensing of current input */
        *norm = CX25821_NORMS;
 
        return 0;
@@ -1297,3 +1720,325 @@ int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
 
        return 0;
 }
+
+static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
+                                unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       int command = 0;
+       struct upstream_user_struct *data_from_user;
+
+       data_from_user = (struct upstream_user_struct *)arg;
+
+       if (!data_from_user) {
+              printk
+                  ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+                   __func__);
+              return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != UPSTREAM_START_VIDEO &&
+              command != UPSTREAM_STOP_VIDEO)
+              return 0;
+
+       dev->input_filename = data_from_user->input_filename;
+       dev->input_audiofilename = data_from_user->input_filename;
+       dev->vid_stdname = data_from_user->vid_stdname;
+       dev->pixel_format = data_from_user->pixel_format;
+       dev->channel_select = data_from_user->channel_select;
+       dev->command = data_from_user->command;
+
+       switch (command) {
+       case UPSTREAM_START_VIDEO:
+              cx25821_start_upstream_video_ch1(dev, data_from_user);
+              break;
+
+       case UPSTREAM_STOP_VIDEO:
+              cx25821_stop_upstream_video_ch1(dev);
+              break;
+       }
+
+       return 0;
+}
+
+static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       int command = 0;
+       struct upstream_user_struct *data_from_user;
+
+       data_from_user = (struct upstream_user_struct *)arg;
+
+       if (!data_from_user) {
+              printk
+                  ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+                   __func__);
+              return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != UPSTREAM_START_VIDEO &&
+              command != UPSTREAM_STOP_VIDEO)
+              return 0;
+
+       dev->input_filename_ch2 = data_from_user->input_filename;
+       dev->input_audiofilename = data_from_user->input_filename;
+       dev->vid_stdname_ch2 = data_from_user->vid_stdname;
+       dev->pixel_format_ch2 = data_from_user->pixel_format;
+       dev->channel_select_ch2 = data_from_user->channel_select;
+       dev->command_ch2 = data_from_user->command;
+
+       switch (command) {
+       case UPSTREAM_START_VIDEO:
+              cx25821_start_upstream_video_ch2(dev, data_from_user);
+              break;
+
+       case UPSTREAM_STOP_VIDEO:
+              cx25821_stop_upstream_video_ch2(dev);
+              break;
+       }
+
+       return 0;
+}
+
+static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       int command = 0;
+       struct upstream_user_struct *data_from_user;
+
+       data_from_user = (struct upstream_user_struct *)arg;
+
+       if (!data_from_user) {
+              printk
+                  ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+                   __func__);
+              return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != UPSTREAM_START_AUDIO &&
+              command != UPSTREAM_STOP_AUDIO)
+              return 0;
+
+       dev->input_filename = data_from_user->input_filename;
+       dev->input_audiofilename = data_from_user->input_filename;
+       dev->vid_stdname = data_from_user->vid_stdname;
+       dev->pixel_format = data_from_user->pixel_format;
+       dev->channel_select = data_from_user->channel_select;
+       dev->command = data_from_user->command;
+
+       switch (command) {
+       case UPSTREAM_START_AUDIO:
+              cx25821_start_upstream_audio(dev, data_from_user);
+              break;
+
+       case UPSTREAM_STOP_AUDIO:
+              cx25821_stop_upstream_audio(dev);
+              break;
+       }
+
+       return 0;
+}
+
+static long video_ioctl_set(struct file *file, unsigned int cmd,
+                          unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       struct downstream_user_struct *data_from_user;
+       int command;
+       int width = 720;
+       int selected_channel = 0, pix_format = 0, i = 0;
+       int cif_enable = 0, cif_width = 0;
+       u32 value = 0;
+
+       data_from_user = (struct downstream_user_struct *)arg;
+
+       if (!data_from_user) {
+              printk(
+              "cx25821 in %s(): User data is INVALID. Returning.\n",
+              __func__);
+              return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
+          && command != ENABLE_CIF_RESOLUTION && command != REG_READ
+          && command != REG_WRITE && command != MEDUSA_READ
+          && command != MEDUSA_WRITE) {
+              return 0;
+       }
+
+       switch (command) {
+       case SET_VIDEO_STD:
+              dev->tvnorm =
+                  !strcmp(data_from_user->vid_stdname,
+                          "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
+              medusa_set_videostandard(dev);
+              break;
+
+       case SET_PIXEL_FORMAT:
+              selected_channel = data_from_user->decoder_select;
+              pix_format = data_from_user->pixel_format;
+
+              if (!(selected_channel <= 7 && selected_channel >= 0)) {
+                      selected_channel -= 4;
+                      selected_channel = selected_channel % 8;
+              }
+
+              if (selected_channel >= 0)
+                      cx25821_set_pixel_format(dev, selected_channel,
+                                               pix_format);
+
+              break;
+
+       case ENABLE_CIF_RESOLUTION:
+              selected_channel = data_from_user->decoder_select;
+              cif_enable = data_from_user->cif_resolution_enable;
+              cif_width = data_from_user->cif_width;
+
+              if (cif_enable) {
+                      if (dev->tvnorm & V4L2_STD_PAL_BG
+                          || dev->tvnorm & V4L2_STD_PAL_DK)
+                              width = 352;
+                      else
+                              width = (cif_width == 320
+                                       || cif_width == 352) ? cif_width : 320;
+              }
+
+              if (!(selected_channel <= 7 && selected_channel >= 0)) {
+                      selected_channel -= 4;
+                      selected_channel = selected_channel % 8;
+              }
+
+              if (selected_channel <= 7 && selected_channel >= 0) {
+                      dev->channels[selected_channel].
+                              use_cif_resolution = cif_enable;
+                      dev->channels[selected_channel].cif_width = width;
+              } else {
+                      for (i = 0; i < VID_CHANNEL_NUM; i++) {
+                              dev->channels[i].use_cif_resolution =
+                                      cif_enable;
+                              dev->channels[i].cif_width = width;
+                      }
+              }
+
+              medusa_set_resolution(dev, width, selected_channel);
+              break;
+       case REG_READ:
+              data_from_user->reg_data = cx_read(data_from_user->reg_address);
+              break;
+       case REG_WRITE:
+              cx_write(data_from_user->reg_address, data_from_user->reg_data);
+              break;
+       case MEDUSA_READ:
+              value =
+                  cx25821_i2c_read(&dev->i2c_bus[0],
+                                   (u16) data_from_user->reg_address,
+                                   &data_from_user->reg_data);
+              break;
+       case MEDUSA_WRITE:
+              cx25821_i2c_write(&dev->i2c_bus[0],
+                                (u16) data_from_user->reg_address,
+                                data_from_user->reg_data);
+              break;
+       }
+
+       return 0;
+}
+
+static long cx25821_video_ioctl(struct file *file,
+                              unsigned int cmd, unsigned long arg)
+{
+       int  ret = 0;
+
+       struct cx25821_fh  *fh  = file->private_data;
+
+       /* check to see if it's the video upstream */
+       if (fh->channel_id == SRAM_CH09) {
+              ret = video_ioctl_upstream9(file, cmd, arg);
+              return ret;
+       } else if (fh->channel_id == SRAM_CH10) {
+              ret = video_ioctl_upstream10(file, cmd, arg);
+              return ret;
+       } else if (fh->channel_id == SRAM_CH11) {
+              ret = video_ioctl_upstream11(file, cmd, arg);
+              ret = video_ioctl_set(file, cmd, arg);
+              return ret;
+       }
+
+    return video_ioctl2(file, cmd, arg);
+}
+
+/* exported stuff */
+static const struct v4l2_file_operations video_fops = {
+       .owner = THIS_MODULE,
+       .open = video_open,
+       .release = video_release,
+       .read = video_read,
+       .poll = video_poll,
+       .mmap = cx25821_video_mmap,
+       .ioctl = cx25821_video_ioctl,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap = cx25821_vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
+       .vidioc_querybuf = cx25821_vidioc_querybuf,
+       .vidioc_qbuf = cx25821_vidioc_qbuf,
+       .vidioc_dqbuf = vidioc_dqbuf,
+#ifdef TUNER_FLAG
+       .vidioc_s_std = cx25821_vidioc_s_std,
+       .vidioc_querystd = cx25821_vidioc_querystd,
+#endif
+       .vidioc_cropcap = cx25821_vidioc_cropcap,
+       .vidioc_s_crop = cx25821_vidioc_s_crop,
+       .vidioc_g_crop = cx25821_vidioc_g_crop,
+       .vidioc_enum_input = cx25821_vidioc_enum_input,
+       .vidioc_g_input = cx25821_vidioc_g_input,
+       .vidioc_s_input = cx25821_vidioc_s_input,
+       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
+       .vidioc_s_ctrl = vidioc_s_ctrl,
+       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
+       .vidioc_streamon = vidioc_streamon,
+       .vidioc_streamoff = vidioc_streamoff,
+       .vidioc_log_status = vidioc_log_status,
+       .vidioc_g_priority = cx25821_vidioc_g_priority,
+       .vidioc_s_priority = cx25821_vidioc_s_priority,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf = cx25821_vidiocgmbuf,
+#endif
+#ifdef TUNER_FLAG
+       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
+       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
+       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
+       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
+#endif
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register = cx25821_vidioc_g_register,
+       .vidioc_s_register = cx25821_vidioc_s_register,
+#endif
+};
+
+struct video_device cx25821_videoioctl_template = {
+              .name = "cx25821-videoioctl",
+              .fops = &video_fops,
+              .ioctl_ops = &video_ioctl_ops,
+              .tvnorms = CX25821_NORMS,
+              .current_norm = V4L2_STD_NTSC_M,
+};
index 0bddc02be57d6df2a77acd0b47019db477c8e600..cc6034b1a95d717ca632c1e95a70d49307449c45 100644 (file)
@@ -54,7 +54,7 @@
        printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
     } while (0)
 
-//For IOCTL to identify running upstream
+/* For IOCTL to identify running upstream */
 #define UPSTREAM_START_VIDEO        700
 #define UPSTREAM_STOP_VIDEO         701
 #define UPSTREAM_START_AUDIO        702
@@ -80,19 +80,8 @@ extern struct sram_channel *channel7;
 extern struct sram_channel *channel9;
 extern struct sram_channel *channel10;
 extern struct sram_channel *channel11;
-extern struct video_device cx25821_video_template0;
-extern struct video_device cx25821_video_template1;
-extern struct video_device cx25821_video_template2;
-extern struct video_device cx25821_video_template3;
-extern struct video_device cx25821_video_template4;
-extern struct video_device cx25821_video_template5;
-extern struct video_device cx25821_video_template6;
-extern struct video_device cx25821_video_template7;
-extern struct video_device cx25821_video_template9;
-extern struct video_device cx25821_video_template10;
-extern struct video_device cx25821_video_template11;
 extern struct video_device cx25821_videoioctl_template;
-//extern const u32 *ctrl_classes[];
+/* extern const u32 *ctrl_classes[]; */
 
 extern unsigned int vid_limit;
 
@@ -113,7 +102,7 @@ extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm);
 extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
                   unsigned int bit);
 extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit);
-extern int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit);
+extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit);
 extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
                     unsigned int bits);
 extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input);
@@ -126,8 +115,7 @@ extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width,
                             unsigned int height, enum v4l2_field field);
 extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status);
 extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num);
-extern int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
-                                 struct video_device *video_template);
+extern int cx25821_video_register(struct cx25821_dev *dev);
 extern int cx25821_get_format_size(void);
 
 extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
diff --git a/drivers/staging/cx25821/cx25821-video0.c b/drivers/staging/cx25821/cx25821-video0.c
deleted file mode 100644 (file)
index 0be2cc1..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH00];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH00]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH00;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO0))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH00]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO0)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = PIXEL_FRMT_422;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH00] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH00] = 0;
-       }
-       dev->cif_width[SRAM_CH00] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH00);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH00].count;
-
-       return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH00];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 0 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH00);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template0 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video1.c b/drivers/staging/cx25821/cx25821-video1.c
deleted file mode 100644 (file)
index b0bae62..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH01];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH01]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH01;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO1))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH01]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel1->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO1);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO1)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO1);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH01, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH01] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH01] = 0;
-       }
-       dev->cif_width[SRAM_CH01] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH01);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH01].count;
-
-       return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH01];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 1 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH01);
-}
-
-//exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template1 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video2.c b/drivers/staging/cx25821/cx25821-video2.c
deleted file mode 100644 (file)
index 400cdb8..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH02];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH02]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH02;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO2))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH02]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel2->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO2);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO2)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO2);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH02, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH02] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH02] = 0;
-       }
-       dev->cif_width[SRAM_CH02] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH02);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH02].count;
-
-       return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH02];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-
-       cx25821_call_all(dev, core, log_status);
-
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 2 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH02);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template2 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video3.c b/drivers/staging/cx25821/cx25821-video3.c
deleted file mode 100644 (file)
index 3b216ed..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH03];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH03]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH03;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO3))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH03]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel3->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO3);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO3)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO3);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH03, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH03] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH03] = 0;
-       }
-       dev->cif_width[SRAM_CH03] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH03);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH03].count;
-
-       return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH03];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 3 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH03);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template3 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video4.c b/drivers/staging/cx25821/cx25821-video4.c
deleted file mode 100644 (file)
index f7b08c5..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH04];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH04]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH04;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO4))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH04]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel4->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO4);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO4)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO4);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       // check priority
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH04, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH04] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH04] = 0;
-       }
-       dev->cif_width[SRAM_CH04] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH04);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH04].count;
-
-       return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH04];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 4 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH04);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template4 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video5.c b/drivers/staging/cx25821/cx25821-video5.c
deleted file mode 100644 (file)
index 5937033..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH05];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH05]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH05;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO5))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH05]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel5->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO5);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO5)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO5);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH05, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH05] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH05] = 0;
-       }
-       dev->cif_width[SRAM_CH05] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH05);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH05].count;
-
-       return ret_val;
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH05];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 5 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH05);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template5 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video6.c b/drivers/staging/cx25821/cx25821-video6.c
deleted file mode 100644 (file)
index 4db2eb8..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH06];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH06]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH06;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO6))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH06]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel6->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO6);
-       }
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO6)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO6);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH06, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH06] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH06] = 0;
-       }
-       dev->cif_width[SRAM_CH06] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH06);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH06].count;
-
-       return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH06];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 6 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH06);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template6 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video7.c b/drivers/staging/cx25821/cx25821-video7.c
deleted file mode 100644 (file)
index 5e4a769..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH07];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH07]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = SRAM_CH07;
-       pix_format =
-           (dev->pixel_formats[dev->channel_opened] ==
-            PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO7))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-               if (buf->vb.state == VIDEOBUF_DONE) {
-                       struct cx25821_dev *dev = fh->dev;
-
-                       if (dev && dev->use_cif_resolution[SRAM_CH07]) {
-                               u8 cam_id = *((char *)buf->vb.baddr + 3);
-                               memcpy((char *)buf->vb.baddr,
-                                      (char *)buf->vb.baddr + (fh->width * 2),
-                                      (fh->width * 2));
-                               *((char *)buf->vb.baddr + 3) = cam_id;
-                       }
-               }
-
-               return POLLIN | POLLRDNORM;
-       }
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       cx_write(channel7->dma_ctl, 0); /* FIFO and RISC disable */
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO7);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO7)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO7);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-       int pix_format = 0;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->vidq.field = f->fmt.pix.field;
-
-       // check if width and height is valid based on set standard
-       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-               fh->width = f->fmt.pix.width;
-       }
-
-       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-               fh->height = f->fmt.pix.height;
-       }
-
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-               pix_format = PIXEL_FRMT_411;
-       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-               pix_format = PIXEL_FRMT_422;
-       else
-               return -EINVAL;
-
-       cx25821_set_pixel_format(dev, SRAM_CH07, pix_format);
-
-       // check if cif resolution
-       if (fh->width == 320 || fh->width == 352) {
-               dev->use_cif_resolution[SRAM_CH07] = 1;
-       } else {
-               dev->use_cif_resolution[SRAM_CH07] = 0;
-       }
-       dev->cif_width[SRAM_CH07] = fh->width;
-       medusa_set_resolution(dev, fh->width, SRAM_CH07);
-
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       int ret_val = 0;
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-       p->sequence = dev->vidq[SRAM_CH07].count;
-
-       return ret_val;
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH07];
-       u32 tmp = 0;
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-
-       tmp = cx_read(sram_ch->dma_ctl);
-       printk(KERN_INFO "Video input 7 is %s\n",
-              (tmp & 0x11) ? "streaming" : "stopped");
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return cx25821_set_control(dev, ctl, SRAM_CH07);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template7 = {
-       .name = "cx25821-video",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-videoioctl.c b/drivers/staging/cx25821/cx25821-videoioctl.c
deleted file mode 100644 (file)
index d16807d..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[VIDEO_IOCTL_CH];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[VIDEO_IOCTL_CH]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       u32 pix_format;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = VIDEO_IOCTL_CH;
-       pix_format = V4L2_PIX_FMT_YUYV;
-       fh->fmt = format_by_fourcc(pix_format);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN | POLLRDNORM;
-
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width = f->fmt.pix.width;
-       fh->height = f->fmt.pix.height;
-       fh->vidq.field = f->fmt.pix.field;
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct cx25821_fh *fh = priv;
-       return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static long video_ioctl_set(struct file *file, unsigned int cmd,
-                           unsigned long arg)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct downstream_user_struct *data_from_user;
-       int command;
-       int width = 720;
-       int selected_channel = 0, pix_format = 0, i = 0;
-       int cif_enable = 0, cif_width = 0;
-       u32 value = 0;
-
-       data_from_user = (struct downstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               printk("cx25821 in %s(): User data is INVALID. Returning.\n",
-                      __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
-           && command != ENABLE_CIF_RESOLUTION && command != REG_READ
-           && command != REG_WRITE && command != MEDUSA_READ
-           && command != MEDUSA_WRITE) {
-               return 0;
-       }
-
-       switch (command) {
-       case SET_VIDEO_STD:
-               dev->tvnorm =
-                   !strcmp(data_from_user->vid_stdname,
-                           "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
-               medusa_set_videostandard(dev);
-               break;
-
-       case SET_PIXEL_FORMAT:
-               selected_channel = data_from_user->decoder_select;
-               pix_format = data_from_user->pixel_format;
-
-               if (!(selected_channel <= 7 && selected_channel >= 0)) {
-                       selected_channel -= 4;
-                       selected_channel = selected_channel % 8;
-               }
-
-               if (selected_channel >= 0)
-                       cx25821_set_pixel_format(dev, selected_channel,
-                                                pix_format);
-
-               break;
-
-       case ENABLE_CIF_RESOLUTION:
-               selected_channel = data_from_user->decoder_select;
-               cif_enable = data_from_user->cif_resolution_enable;
-               cif_width = data_from_user->cif_width;
-
-               if (cif_enable) {
-                       if (dev->tvnorm & V4L2_STD_PAL_BG
-                           || dev->tvnorm & V4L2_STD_PAL_DK)
-                               width = 352;
-                       else
-                               width = (cif_width == 320
-                                        || cif_width == 352) ? cif_width : 320;
-               }
-
-               if (!(selected_channel <= 7 && selected_channel >= 0)) {
-                       selected_channel -= 4;
-                       selected_channel = selected_channel % 8;
-               }
-
-               if (selected_channel <= 7 && selected_channel >= 0) {
-                       dev->use_cif_resolution[selected_channel] = cif_enable;
-                       dev->cif_width[selected_channel] = width;
-               } else {
-                       for (i = 0; i < VID_CHANNEL_NUM; i++) {
-                               dev->use_cif_resolution[i] = cif_enable;
-                               dev->cif_width[i] = width;
-                       }
-               }
-
-               medusa_set_resolution(dev, width, selected_channel);
-               break;
-       case REG_READ:
-               data_from_user->reg_data = cx_read(data_from_user->reg_address);
-               break;
-       case REG_WRITE:
-               cx_write(data_from_user->reg_address, data_from_user->reg_data);
-               break;
-       case MEDUSA_READ:
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    (u16) data_from_user->reg_address,
-                                    &data_from_user->reg_data);
-               break;
-       case MEDUSA_WRITE:
-               cx25821_i2c_write(&dev->i2c_bus[0],
-                                 (u16) data_from_user->reg_address,
-                                 data_from_user->reg_data);
-               break;
-       }
-
-       return 0;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl_set,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_videoioctl_template = {
-       .name = "cx25821-videoioctl",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-vidups10.c b/drivers/staging/cx25821/cx25821-vidups10.c
deleted file mode 100644 (file)
index c746a17..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH10];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH10]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = 9;
-       fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO10))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       //cx_write(channel10->dma_ctl, 0);
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO10);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO10)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO10);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
-                                  unsigned long arg)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-       int command = 0;
-       struct upstream_user_struct *data_from_user;
-
-       data_from_user = (struct upstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               printk
-                   ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
-                    __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) {
-               return 0;
-       }
-
-       dev->input_filename_ch2 = data_from_user->input_filename;
-       dev->input_audiofilename = data_from_user->input_filename;
-       dev->vid_stdname_ch2 = data_from_user->vid_stdname;
-       dev->pixel_format_ch2 = data_from_user->pixel_format;
-       dev->channel_select_ch2 = data_from_user->channel_select;
-       dev->command_ch2 = data_from_user->command;
-
-       switch (command) {
-       case UPSTREAM_START_VIDEO:
-               cx25821_start_upstream_video_ch2(dev, data_from_user);
-               break;
-
-       case UPSTREAM_STOP_VIDEO:
-               cx25821_stop_upstream_video_ch2(dev);
-               break;
-       }
-
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width = f->fmt.pix.width;
-       fh->height = f->fmt.pix.height;
-       fh->vidq.field = f->fmt.pix.field;
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct cx25821_fh *fh = priv;
-       return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return 0;
-}
-
-//exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl_upstream10,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template10 = {
-       .name = "cx25821-upstream10",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-vidups9.c b/drivers/staging/cx25821/cx25821-vidups9.c
deleted file mode 100644 (file)
index 466e0f3..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 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.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-       struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
-       struct cx25821_buffer *prev;
-       struct cx25821_fh *fh = vq->priv_data;
-       struct cx25821_dev *dev = fh->dev;
-       struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH09];
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
-
-       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-                       buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx25821_start_video_dma(dev, q, buf,
-                                       &dev->sram_channels[SRAM_CH09]);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count = q->count++;
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-               dprintk(2,
-                       "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-                       buf, buf->vb.i, buf->count, q->count);
-       } else {
-               prev =
-                   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-               if (prev->vb.width == buf->vb.width
-                   && prev->vb.height == buf->vb.height
-                   && prev->fmt == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2,
-                               "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-                               buf, buf->vb.i, buf->count);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-                               buf->vb.i);
-               }
-       }
-
-       if (list_empty(&q->active)) {
-               dprintk(2, "active queue empty!\n");
-       }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-       .buf_setup = cx25821_buffer_setup,
-       .buf_prepare = cx25821_buffer_prepare,
-       .buf_queue = buffer_queue,
-       .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct cx25821_dev *dev = video_drvdata(file);
-       struct cx25821_fh *fh;
-       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-               v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       lock_kernel();
-
-       file->private_data = fh;
-       fh->dev = dev;
-       fh->type = type;
-       fh->width = 720;
-
-       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-               fh->height = 576;
-       else
-               fh->height = 480;
-
-       dev->channel_opened = 8;
-       fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-       v4l2_prio_open(&dev->prio, &fh->prio);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                              &dev->pci->dev, &dev->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct cx25821_buffer), fh);
-
-       dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
-
-       return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-                         loff_t * ppos)
-{
-       struct cx25821_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO9))
-                       return -EBUSY;
-
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-                              struct poll_table_struct *wait)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_buffer *buf;
-
-       if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
-               buf = list_entry(fh->vidq.stream.next,
-                                struct cx25821_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       return POLLERR;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-
-       //stop the risc engine and fifo
-       //cx_write(channel9->dma_ctl, 0);
-
-       /* stop video capture */
-       if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
-               videobuf_queue_cancel(&fh->vidq);
-               cx25821_res_free(dev, fh, RESOURCE_VIDEO9);
-       }
-
-       if (fh->vidq.read_buf) {
-               cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
-
-       videobuf_mmap_free(&fh->vidq);
-
-       v4l2_prio_close(&dev->prio, fh->prio);
-
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-
-       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(i != fh->type)) {
-               return -EINVAL;
-       }
-
-       if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO9)))) {
-               return -EBUSY;
-       }
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = fh->dev;
-       int err, res;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = cx25821_get_resource(fh, RESOURCE_VIDEO9);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       cx25821_res_free(dev, fh, res);
-       return 0;
-}
-
-static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
-                                 unsigned long arg)
-{
-       struct cx25821_fh *fh = file->private_data;
-       struct cx25821_dev *dev = fh->dev;
-       int command = 0;
-       struct upstream_user_struct *data_from_user;
-
-       data_from_user = (struct upstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               printk
-                   ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
-                    __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) {
-               return 0;
-       }
-
-       dev->input_filename = data_from_user->input_filename;
-       dev->input_audiofilename = data_from_user->input_filename;
-       dev->vid_stdname = data_from_user->vid_stdname;
-       dev->pixel_format = data_from_user->pixel_format;
-       dev->channel_select = data_from_user->channel_select;
-       dev->command = data_from_user->command;
-
-       switch (command) {
-       case UPSTREAM_START_VIDEO:
-               cx25821_start_upstream_video_ch1(dev, data_from_user);
-               break;
-
-       case UPSTREAM_STOP_VIDEO:
-               cx25821_stop_upstream_video_ch1(dev);
-               break;
-       }
-
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct cx25821_fh *fh = priv;
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       int err;
-
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       dprintk(2, "%s()\n", __func__);
-       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-       if (0 != err)
-               return err;
-       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width = f->fmt.pix.width;
-       fh->height = f->fmt.pix.height;
-       fh->vidq.field = f->fmt.pix.field;
-       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-               fh->height, fh->vidq.field);
-       cx25821_call_all(dev, video, s_fmt, f);
-       return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct cx25821_fh *fh = priv;
-       return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       char name[32 + 2];
-
-       snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
-       cx25821_call_all(dev, core, log_status);
-       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
-       return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctl)
-{
-       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-       struct cx25821_fh *fh = priv;
-       int err;
-       if (fh) {
-               err = v4l2_prio_check(&dev->prio, fh->prio);
-               if (0 != err)
-                       return err;
-       }
-
-       return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-       .owner = THIS_MODULE,
-       .open = video_open,
-       .release = video_release,
-       .read = video_read,
-       .poll = video_poll,
-       .mmap = cx25821_video_mmap,
-       .ioctl = video_ioctl_upstream9,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap = cx25821_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
-       .vidioc_querybuf = cx25821_vidioc_querybuf,
-       .vidioc_qbuf = cx25821_vidioc_qbuf,
-       .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-       .vidioc_s_std = cx25821_vidioc_s_std,
-       .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-       .vidioc_cropcap = cx25821_vidioc_cropcap,
-       .vidioc_s_crop = cx25821_vidioc_s_crop,
-       .vidioc_g_crop = cx25821_vidioc_g_crop,
-       .vidioc_enum_input = cx25821_vidioc_enum_input,
-       .vidioc_g_input = cx25821_vidioc_g_input,
-       .vidioc_s_input = cx25821_vidioc_s_input,
-       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-       .vidioc_s_ctrl = vidioc_s_ctrl,
-       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
-       .vidioc_streamon = vidioc_streamon,
-       .vidioc_streamoff = vidioc_streamoff,
-       .vidioc_log_status = vidioc_log_status,
-       .vidioc_g_priority = cx25821_vidioc_g_priority,
-       .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
-       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
-       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
-       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register = cx25821_vidioc_g_register,
-       .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template9 = {
-       .name = "cx25821-upstream9",
-       .fops = &video_fops,
-       .ioctl_ops = &video_ioctl_ops,
-       .tvnorms = CX25821_NORMS,
-       .current_norm = V4L2_STD_NTSC_M,
-};
index cf2286d83b6aaa847b13ef0c5f30a02da756b615..1b628f61578a1e3f60878925461bbe4571f9b2e0 100644 (file)
@@ -61,7 +61,7 @@
 #define FALSE   0
 #define LINE_SIZE_D1    1440
 
-// Number of decoders and encoders
+/* Number of decoders and encoders */
 #define MAX_DECODERS            8
 #define MAX_ENCODERS            2
 #define QUAD_DECODERS           4
@@ -139,6 +139,7 @@ struct cx25821_fh {
        /* video capture */
        struct cx25821_fmt *fmt;
        unsigned int width, height;
+    int channel_id;
 
        /* vbi capture */
        struct videobuf_queue vidq;
@@ -236,13 +237,34 @@ struct cx25821_data {
        struct sram_channel *channel;
 };
 
+struct cx25821_channel {
+       struct v4l2_prio_state prio;
+
+       int ctl_bright;
+       int ctl_contrast;
+       int ctl_hue;
+       int ctl_saturation;
+
+       struct cx25821_data timeout_data;
+
+       struct video_device *video_dev;
+       struct cx25821_dmaqueue vidq;
+
+       struct sram_channel *sram_channels;
+
+       struct mutex lock;
+       int resources;
+
+       int pixel_formats;
+       int use_cif_resolution;
+       int cif_width;
+};
+
 struct cx25821_dev {
        struct list_head devlist;
        atomic_t refcount;
        struct v4l2_device v4l2_dev;
 
-       struct v4l2_prio_state prio;
-
        /* pci stuff */
        struct pci_dev *pci;
        unsigned char pci_rev, pci_lat;
@@ -261,13 +283,12 @@ struct cx25821_dev {
        int nr;
        struct mutex lock;
 
+    struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
+
        /* board details */
        unsigned int board;
        char name[32];
 
-       /* sram configuration */
-       struct sram_channel *sram_channels;
-
        /* Analog video */
        u32 resources;
        unsigned int input;
@@ -282,13 +303,6 @@ struct cx25821_dev {
        unsigned char videc_addr;
        unsigned short _max_num_decoders;
 
-       int ctl_bright;
-       int ctl_contrast;
-       int ctl_hue;
-       int ctl_saturation;
-
-       struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
-
        /* Analog Audio Upstream */
        int _audio_is_running;
        int _audiopixel_format;
@@ -297,7 +311,7 @@ struct cx25821_dev {
        int _audio_lines_count;
        int _audioframe_count;
        int _audio_upstream_channel_select;
-       int _last_index_irq;    //The last interrupt index processed.
+       int _last_index_irq;    /* The last interrupt index processed. */
 
        __le32 *_risc_audio_jmp_addr;
        __le32 *_risc_virt_start_addr;
@@ -313,12 +327,10 @@ struct cx25821_dev {
 
        /* V4l */
        u32 freq;
-       struct video_device *video_dev[MAX_VID_CHANNEL_NUM];
        struct video_device *vbi_dev;
        struct video_device *radio_dev;
        struct video_device *ioctl_dev;
 
-       struct cx25821_dmaqueue vidq[MAX_VID_CHANNEL_NUM];
        spinlock_t slock;
 
        /* Video Upstream */
@@ -401,9 +413,6 @@ struct cx25821_dev {
        int pixel_format;
        int channel_select;
        int command;
-       int pixel_formats[VID_CHANNEL_NUM];
-       int use_cif_resolution[VID_CHANNEL_NUM];
-       int cif_width[VID_CHANNEL_NUM];
        int channel_opened;
 };
 
@@ -482,7 +491,7 @@ struct sram_channel {
        u32 fld_aud_fifo_en;
        u32 fld_aud_risc_en;
 
-       //For Upstream Video
+       /* For Upstream Video */
        u32 vid_fmt_ctl;
        u32 vid_active_ctl1;
        u32 vid_active_ctl2;
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig
new file mode 100644 (file)
index 0000000..968c2ad
--- /dev/null
@@ -0,0 +1,110 @@
+#
+# LIRC driver(s) configuration
+#
+menuconfig LIRC_STAGING
+       bool "Linux Infrared Remote Control IR receiver/transmitter drivers"
+       help
+         Say Y here, and all supported Linux Infrared Remote Control IR and
+         RF receiver and transmitter drivers will be displayed. When paired
+         with a remote control and the lirc daemon, the receiver drivers
+         allow control of your Linux system via remote control.
+
+if LIRC_STAGING
+
+config LIRC_BT829
+        tristate "BT829 based hardware"
+       depends on LIRC_STAGING
+       help
+         Driver for the IR interface on BT829-based hardware
+
+config LIRC_ENE0100
+       tristate "ENE KB3924/ENE0100 CIR Port Reciever"
+       depends on LIRC_STAGING
+       help
+         This is a driver for CIR port handled by ENE KB3924 embedded
+         controller found on some notebooks.
+         It appears on PNP list as ENE0100.
+
+config LIRC_I2C
+       tristate "I2C Based IR Receivers"
+       depends on LIRC_STAGING
+       help
+         Driver for I2C-based IR receivers, such as those commonly
+         found onboard Hauppauge PVR-150/250/350 video capture cards
+
+config LIRC_IGORPLUGUSB
+       tristate "Igor Cesko's USB IR Receiver"
+       depends on LIRC_STAGING && USB
+       help
+         Driver for Igor Cesko's USB IR Receiver
+
+config LIRC_IMON
+       tristate "Legacy SoundGraph iMON Receiver and Display"
+       depends on LIRC_STAGING
+       help
+         Driver for the original SoundGraph iMON IR Receiver and Display
+
+         Current generation iMON devices use the input layer imon driver.
+
+config LIRC_IT87
+       tristate "ITE IT87XX CIR Port Receiver"
+       depends on LIRC_STAGING
+       help
+         Driver for the ITE IT87xx IR Receiver
+
+config LIRC_ITE8709
+       tristate "ITE8709 CIR Port Receiver"
+       depends on LIRC_STAGING && PNP
+       help
+         Driver for the ITE8709 IR Receiver
+
+config LIRC_PARALLEL
+       tristate "Homebrew Parallel Port Receiver"
+       depends on LIRC_STAGING && !SMP
+       help
+         Driver for Homebrew Parallel Port Receivers
+
+config LIRC_SASEM
+       tristate "Sasem USB IR Remote"
+       depends on LIRC_STAGING
+       help
+         Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module
+
+config LIRC_SERIAL
+       tristate "Homebrew Serial Port Receiver"
+       depends on LIRC_STAGING
+       help
+         Driver for Homebrew Serial Port Receivers
+
+config LIRC_SERIAL_TRANSMITTER
+       bool "Serial Port Transmitter"
+       default y
+       depends on LIRC_SERIAL
+       help
+         Serial Port Transmitter support
+
+config LIRC_SIR
+       tristate "Built-in SIR IrDA port"
+       depends on LIRC_STAGING
+       help
+         Driver for the SIR IrDA port
+
+config LIRC_STREAMZAP
+       tristate "Streamzap PC Receiver"
+       depends on LIRC_STAGING
+       help
+         Driver for the Streamzap PC Receiver
+
+config LIRC_TTUSBIR
+       tristate "Technotrend USB IR Receiver"
+       depends on LIRC_STAGING && USB
+       help
+         Driver for the Technotrend USB IR Receiver
+
+config LIRC_ZILOG
+       tristate "Zilog/Hauppauge IR Transmitter"
+       depends on LIRC_STAGING
+       help
+         Driver for the Zilog/Hauppauge IR Transmitter, found on
+         PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
+endif
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile
new file mode 100644 (file)
index 0000000..a019182
--- /dev/null
@@ -0,0 +1,19 @@
+# Makefile for the lirc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_LIRC_BT829)       += lirc_bt829.o
+obj-$(CONFIG_LIRC_ENE0100)     += lirc_ene0100.o
+obj-$(CONFIG_LIRC_I2C)         += lirc_i2c.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
+obj-$(CONFIG_LIRC_SIR)         += lirc_sir.o
+obj-$(CONFIG_LIRC_STREAMZAP)   += lirc_streamzap.o
+obj-$(CONFIG_LIRC_TTUSBIR)     += lirc_ttusbir.o
+obj-$(CONFIG_LIRC_ZILOG)       += lirc_zilog.o
diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO
new file mode 100644 (file)
index 0000000..b6cb593
--- /dev/null
@@ -0,0 +1,8 @@
+- All drivers should either be ported to ir-core, or dropped entirely
+  (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an
+  example of a previously completed port).
+
+Please send patches to:
+Jarod Wilson <jarod@wilsonet.com>
+Greg Kroah-Hartman <greg@kroah.com>
+
diff --git a/drivers/staging/lirc/TODO.lirc_i2c b/drivers/staging/lirc/TODO.lirc_i2c
new file mode 100644 (file)
index 0000000..1f0a6ff
--- /dev/null
@@ -0,0 +1,3 @@
+lirc_i2c provides support for some drivers that have already a RC
+driver under drivers/media/video. It should be integrated into those
+drivers, in special with drivers/media/video/ir-kbd-i2c.c.
diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c
new file mode 100644 (file)
index 0000000..3388102
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Remote control driver for the TV-card based on bt829
+ *
+ *  by Leonid Froenchenko <lfroen@galileo.co.il>
+ *
+ *  This program is free software; 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/threads.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <media/lirc_dev.h>
+
+static int poll_main(void);
+static int atir_init_start(void);
+
+static void write_index(unsigned char index, unsigned int value);
+static unsigned int read_index(unsigned char index);
+
+static void do_i2c_start(void);
+static void do_i2c_stop(void);
+
+static void seems_wr_byte(unsigned char al);
+static unsigned char seems_rd_byte(void);
+
+static unsigned int read_index(unsigned char al);
+static void write_index(unsigned char ah, unsigned int edx);
+
+static void cycle_delay(int cycle);
+
+static void do_set_bits(unsigned char bl);
+static unsigned char do_get_bits(void);
+
+#define DATA_PCI_OFF 0x7FFC00
+#define WAIT_CYCLE   20
+
+#define DRIVER_NAME "lirc_bt829"
+
+static int debug;
+#define dprintk(fmt, args...)                                           \
+       do {                                                             \
+               if (debug)                                               \
+                       printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \
+       } while (0)
+
+static int atir_minor;
+static unsigned long pci_addr_phys;
+static unsigned char *pci_addr_lin;
+
+static struct lirc_driver atir_driver;
+
+static struct pci_dev *do_pci_probe(void)
+{
+       struct pci_dev *my_dev;
+       my_dev = pci_get_device(PCI_VENDOR_ID_ATI,
+                               PCI_DEVICE_ID_ATI_264VT, NULL);
+       if (my_dev) {
+               printk(KERN_ERR DRIVER_NAME ": Using device: %s\n",
+                      pci_name(my_dev));
+               pci_addr_phys = 0;
+               if (my_dev->resource[0].flags & IORESOURCE_MEM) {
+                       pci_addr_phys = my_dev->resource[0].start;
+                       printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n",
+                              (unsigned int)pci_addr_phys);
+               }
+               if (pci_addr_phys == 0) {
+                       printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n");
+                       return NULL;
+               }
+       } else {
+               printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n");
+               return NULL;
+       }
+       return my_dev;
+}
+
+static int atir_add_to_buf(void *data, struct lirc_buffer *buf)
+{
+       unsigned char key;
+       int status;
+       status = poll_main();
+       key = (status >> 8) & 0xFF;
+       if (status & 0xFF) {
+               dprintk("reading key %02X\n", key);
+               lirc_buffer_write(buf, &key);
+               return 0;
+       }
+       return -ENODATA;
+}
+
+static int atir_set_use_inc(void *data)
+{
+       dprintk("driver is opened\n");
+       return 0;
+}
+
+static void atir_set_use_dec(void *data)
+{
+       dprintk("driver is closed\n");
+}
+
+int init_module(void)
+{
+       struct pci_dev *pdev;
+
+       pdev = do_pci_probe();
+       if (pdev == NULL)
+               return 1;
+
+       if (!atir_init_start())
+               return 1;
+
+       strcpy(atir_driver.name, "ATIR");
+       atir_driver.minor       = -1;
+       atir_driver.code_length = 8;
+       atir_driver.sample_rate = 10;
+       atir_driver.data        = 0;
+       atir_driver.add_to_buf  = atir_add_to_buf;
+       atir_driver.set_use_inc = atir_set_use_inc;
+       atir_driver.set_use_dec = atir_set_use_dec;
+       atir_driver.dev         = &pdev->dev;
+       atir_driver.owner       = THIS_MODULE;
+
+       atir_minor = lirc_register_driver(&atir_driver);
+       if (atir_minor < 0) {
+               printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n");
+               return atir_minor;
+       }
+       dprintk("driver is registered on minor %d\n", atir_minor);
+
+       return 0;
+}
+
+
+void cleanup_module(void)
+{
+       lirc_unregister_driver(atir_minor);
+}
+
+
+static int atir_init_start(void)
+{
+       pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400);
+       if (pci_addr_lin == 0) {
+               printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n");
+               return 0;
+       }
+       return 1;
+}
+
+static void cycle_delay(int cycle)
+{
+       udelay(WAIT_CYCLE*cycle);
+}
+
+
+static int poll_main()
+{
+       unsigned char status_high, status_low;
+
+       do_i2c_start();
+
+       seems_wr_byte(0xAA);
+       seems_wr_byte(0x01);
+
+       do_i2c_start();
+
+       seems_wr_byte(0xAB);
+
+       status_low = seems_rd_byte();
+       status_high = seems_rd_byte();
+
+       do_i2c_stop();
+
+       return (status_high << 8) | status_low;
+}
+
+static void do_i2c_start(void)
+{
+       do_set_bits(3);
+       cycle_delay(4);
+
+       do_set_bits(1);
+       cycle_delay(7);
+
+       do_set_bits(0);
+       cycle_delay(2);
+}
+
+static void do_i2c_stop(void)
+{
+       unsigned char bits;
+       bits =  do_get_bits() & 0xFD;
+       do_set_bits(bits);
+       cycle_delay(1);
+
+       bits |= 1;
+       do_set_bits(bits);
+       cycle_delay(2);
+
+       bits |= 2;
+       do_set_bits(bits);
+       bits = 3;
+       do_set_bits(bits);
+       cycle_delay(2);
+}
+
+static void seems_wr_byte(unsigned char value)
+{
+       int i;
+       unsigned char reg;
+
+       reg = do_get_bits();
+       for (i = 0; i < 8; i++) {
+               if (value & 0x80)
+                       reg |= 0x02;
+               else
+                       reg &= 0xFD;
+
+               do_set_bits(reg);
+               cycle_delay(1);
+
+               reg |= 1;
+               do_set_bits(reg);
+               cycle_delay(1);
+
+               reg &= 0xFE;
+               do_set_bits(reg);
+               cycle_delay(1);
+               value <<= 1;
+       }
+       cycle_delay(2);
+
+       reg |= 2;
+       do_set_bits(reg);
+
+       reg |= 1;
+       do_set_bits(reg);
+
+       cycle_delay(1);
+       do_get_bits();
+
+       reg &= 0xFE;
+       do_set_bits(reg);
+       cycle_delay(3);
+}
+
+static unsigned char seems_rd_byte(void)
+{
+       int i;
+       int rd_byte;
+       unsigned char bits_2, bits_1;
+
+       bits_1 = do_get_bits() | 2;
+       do_set_bits(bits_1);
+
+       rd_byte = 0;
+       for (i = 0; i < 8; i++) {
+               bits_1 &= 0xFE;
+               do_set_bits(bits_1);
+               cycle_delay(2);
+
+               bits_1 |= 1;
+               do_set_bits(bits_1);
+               cycle_delay(1);
+
+               bits_2 = do_get_bits();
+               if (bits_2 & 2)
+                       rd_byte |= 1;
+
+               rd_byte <<= 1;
+       }
+
+       bits_1 = 0;
+       if (bits_2 == 0)
+               bits_1 |= 2;
+
+       do_set_bits(bits_1);
+       cycle_delay(2);
+
+       bits_1 |= 1;
+       do_set_bits(bits_1);
+       cycle_delay(3);
+
+       bits_1 &= 0xFE;
+       do_set_bits(bits_1);
+       cycle_delay(2);
+
+       rd_byte >>= 1;
+       rd_byte &= 0xFF;
+       return rd_byte;
+}
+
+static void do_set_bits(unsigned char new_bits)
+{
+       int reg_val;
+       reg_val = read_index(0x34);
+       if (new_bits & 2) {
+               reg_val &= 0xFFFFFFDF;
+               reg_val |= 1;
+       } else {
+               reg_val &= 0xFFFFFFFE;
+               reg_val |= 0x20;
+       }
+       reg_val |= 0x10;
+       write_index(0x34, reg_val);
+
+       reg_val = read_index(0x31);
+       if (new_bits & 1)
+               reg_val |= 0x1000000;
+       else
+               reg_val &= 0xFEFFFFFF;
+
+       reg_val |= 0x8000000;
+       write_index(0x31, reg_val);
+}
+
+static unsigned char do_get_bits(void)
+{
+       unsigned char bits;
+       int reg_val;
+
+       reg_val = read_index(0x34);
+       reg_val |= 0x10;
+       reg_val &= 0xFFFFFFDF;
+       write_index(0x34, reg_val);
+
+       reg_val = read_index(0x34);
+       bits = 0;
+       if (reg_val & 8)
+               bits |= 2;
+       else
+               bits &= 0xFD;
+
+       reg_val = read_index(0x31);
+       if (reg_val & 0x1000000)
+               bits |= 1;
+       else
+               bits &= 0xFE;
+
+       return bits;
+}
+
+static unsigned int read_index(unsigned char index)
+{
+       unsigned char *addr;
+       unsigned int value;
+       /*  addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */
+       addr = pci_addr_lin + ((index & 0xFF) << 2);
+       value = readl(addr);
+       return value;
+}
+
+static void write_index(unsigned char index, unsigned int reg_val)
+{
+       unsigned char *addr;
+       addr = pci_addr_lin + ((index & 0xFF) << 2);
+       writel(reg_val, addr);
+}
+
+MODULE_AUTHOR("Froenchenko Leonid");
+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c
new file mode 100644 (file)
index 0000000..a152c52
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@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
+ */
+
+#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 "lirc_ene0100.h"
+
+static int sample_period = 75;
+static int enable_idle = 1;
+static int enable_learning;
+
+static void ene_set_idle(struct ene_device *dev, int idle);
+static void ene_set_inputs(struct ene_device *dev, int enable);
+
+/* read a hardware register */
+static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
+{
+       outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+       outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+       return inb(dev->hw_io + ENE_IO);
+}
+
+/* write a hardware register */
+static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
+{
+       outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+       outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+       outb(value, dev->hw_io + ENE_IO);
+}
+
+/* change specific bits in hardware register */
+static void ene_hw_write_reg_mask(struct ene_device *dev,
+                                 u16 reg, u8 value, u8 mask)
+{
+       u8 regvalue;
+
+       outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+       outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+
+       regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
+       regvalue |= (value & mask);
+       outb(regvalue, dev->hw_io + ENE_IO);
+}
+
+/* read irq status and ack it */
+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer)
+{
+       u8 irq_status;
+       u8 fw_flags1, fw_flags2;
+
+       fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
+
+       if (buffer_pointer)
+               *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH);
+
+       if (dev->hw_revision < ENE_HW_C) {
+               irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+
+               if (!(irq_status & ENEB_IRQ_STATUS_IR))
+                       return 0;
+               ene_hw_write_reg(dev, ENEB_IRQ_STATUS,
+                                irq_status & ~ENEB_IRQ_STATUS_IR);
+
+               /* rev B support only recieving */
+               return ENE_IRQ_RX;
+       }
+
+       irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
+
+       if (!(irq_status & ENEC_IRQ_STATUS))
+               return 0;
+
+       /* original driver does that twice - a workaround ? */
+       ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+       ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+
+       /* clear unknown flag in F8F9 */
+       if (fw_flags2 & ENE_FW2_IRQ_CLR)
+               ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR);
+
+       /* check if this is a TX interrupt */
+       fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+
+       if (fw_flags1 & ENE_FW1_TXIRQ) {
+               ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+               return ENE_IRQ_TX;
+       } else
+               return ENE_IRQ_RX;
+}
+
+static int ene_hw_detect(struct ene_device *dev)
+{
+       u8 chip_major, chip_minor;
+       u8 hw_revision, old_ver;
+       u8 tmp;
+       u8 fw_capabilities;
+
+       tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
+       ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
+
+       chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
+       chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
+
+       ene_hw_write_reg(dev, ENE_HW_UNK, tmp);
+       hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION);
+       old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD);
+
+       if (hw_revision == 0xFF) {
+
+               ene_printk(KERN_WARNING, "device seems to be disabled\n");
+               ene_printk(KERN_WARNING,
+                       "send a mail to lirc-list@lists.sourceforge.net\n");
+               ene_printk(KERN_WARNING, "please attach output of acpidump\n");
+
+               return -ENODEV;
+       }
+
+       if (chip_major == 0x33) {
+               ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n");
+               return -ENODEV;
+       }
+
+       if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
+               dev->hw_revision = ENE_HW_C;
+               ene_printk(KERN_WARNING,
+                      "KB3926C detected, driver support is not complete!\n");
+
+       } else if (old_ver == 0x24 && hw_revision == 0xC0) {
+               dev->hw_revision = ENE_HW_B;
+               ene_printk(KERN_NOTICE, "KB3926B detected\n");
+       } else {
+               dev->hw_revision = ENE_HW_D;
+               ene_printk(KERN_WARNING,
+                       "unknown ENE chip detected, assuming KB3926D\n");
+               ene_printk(KERN_WARNING, "driver support incomplete");
+
+       }
+
+       ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 0x%02x\n",
+               chip_major, chip_minor, old_ver, hw_revision);
+
+
+       /* detect features hardware supports */
+
+       if (dev->hw_revision < ENE_HW_C)
+               return 0;
+
+       fw_capabilities = ene_hw_read_reg(dev, ENE_FW2);
+
+       dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
+       dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING;
+
+       dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable &&
+           fw_capabilities & ENE_FW2_FAN_AS_NRML_IN;
+
+       ene_printk(KERN_NOTICE, "hardware features:\n");
+       ene_printk(KERN_NOTICE,
+               "learning and tx %s, gpio40_learn %s, fan_in %s\n",
+              dev->hw_learning_and_tx_capable ? "on" : "off",
+              dev->hw_gpio40_learning ? "on" : "off",
+              dev->hw_fan_as_normal_input ? "on" : "off");
+
+       if (!dev->hw_learning_and_tx_capable && enable_learning)
+               enable_learning = 0;
+
+       if (dev->hw_learning_and_tx_capable) {
+               ene_printk(KERN_WARNING,
+               "Device supports transmitting, but the driver doesn't\n");
+               ene_printk(KERN_WARNING,
+               "due to lack of hardware to test against.\n");
+               ene_printk(KERN_WARNING,
+               "Send a mail to: lirc-list@lists.sourceforge.net\n");
+       }
+       return 0;
+}
+
+/* hardware initialization */
+static int ene_hw_init(void *data)
+{
+       u8 reg_value;
+       struct ene_device *dev = (struct ene_device *)data;
+       dev->in_use = 1;
+
+       if (dev->hw_revision < ENE_HW_C) {
+               ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+               ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+       } else {
+               reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0;
+               reg_value |= ENEC_IRQ_UNK_EN;
+               reg_value &= ~ENEC_IRQ_STATUS;
+               reg_value |= (dev->irq & ENEC_IRQ_MASK);
+               ene_hw_write_reg(dev, ENEC_IRQ, reg_value);
+               ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63);
+       }
+
+       ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
+       ene_set_inputs(dev, enable_learning);
+
+       /* set sampling period */
+       ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
+
+       /* ack any pending irqs - just in case */
+       ene_hw_irq_status(dev, NULL);
+
+       /* enter idle mode */
+       ene_set_idle(dev, 1);
+
+       /* enable firmware bits */
+       ene_hw_write_reg_mask(dev, ENE_FW1,
+                             ENE_FW1_ENABLE | ENE_FW1_IRQ,
+                             ENE_FW1_ENABLE | ENE_FW1_IRQ);
+       /* clear stats */
+       dev->sample = 0;
+       return 0;
+}
+
+/* this enables gpio40 signal, used if connected to wide band input*/
+static void ene_enable_gpio40(struct ene_device *dev, int enable)
+{
+       ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ?
+                             0 : ENE_CIR_CONF2_GPIO40DIS,
+                             ENE_CIR_CONF2_GPIO40DIS);
+}
+
+/* this enables the classic sampler */
+static void ene_enable_normal_recieve(struct ene_device *dev, int enable)
+{
+       ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0);
+}
+
+/* this enables recieve via fan input */
+static void ene_enable_fan_recieve(struct ene_device *dev, int enable)
+{
+       if (!enable)
+               ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0);
+       else {
+               ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+               ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
+       }
+       dev->fan_input_inuse = enable;
+}
+
+/* determine which input to use*/
+static void ene_set_inputs(struct ene_device *dev, int learning_enable)
+{
+       ene_enable_normal_recieve(dev, 1);
+
+       /* old hardware doesn't support learning mode for sure */
+       if (dev->hw_revision <= ENE_HW_B)
+               return;
+
+       /* reciever not learning capable, still set gpio40 correctly */
+       if (!dev->hw_learning_and_tx_capable) {
+               ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+               return;
+       }
+
+       /* enable learning mode */
+       if (learning_enable) {
+               ene_enable_gpio40(dev, dev->hw_gpio40_learning);
+
+               /* fan input is not used for learning */
+               if (dev->hw_fan_as_normal_input)
+                       ene_enable_fan_recieve(dev, 0);
+
+       /* disable learning mode */
+       } else {
+               if (dev->hw_fan_as_normal_input) {
+                       ene_enable_fan_recieve(dev, 1);
+                       ene_enable_normal_recieve(dev, 0);
+               } else
+                       ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+       }
+
+       /* set few additional settings for this mode */
+       ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ?
+                             ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
+
+       ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ?
+                             ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
+}
+
+/* deinitialization */
+static void ene_hw_deinit(void *data)
+{
+       struct ene_device *dev = (struct ene_device *)data;
+
+       /* disable samplers */
+       ene_enable_normal_recieve(dev, 0);
+
+       if (dev->hw_fan_as_normal_input)
+               ene_enable_fan_recieve(dev, 0);
+
+       /* disable hardware IRQ and firmware flag */
+       ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+
+       ene_set_idle(dev, 1);
+       dev->in_use = 0;
+}
+
+/*  sends current sample to userspace */
+static void send_sample(struct ene_device *dev)
+{
+       int value = abs(dev->sample) & PULSE_MASK;
+
+       if (dev->sample > 0)
+               value |= PULSE_BIT;
+
+       if (!lirc_buffer_full(dev->lirc_driver->rbuf)) {
+               lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value);
+               wake_up(&dev->lirc_driver->rbuf->wait_poll);
+       }
+       dev->sample = 0;
+}
+
+/*  this updates current sample */
+static void update_sample(struct ene_device *dev, int sample)
+{
+       if (!dev->sample)
+               dev->sample = sample;
+       else if (same_sign(dev->sample, sample))
+               dev->sample += sample;
+       else {
+               send_sample(dev);
+               dev->sample = sample;
+       }
+}
+
+/* enable or disable idle mode */
+static void ene_set_idle(struct ene_device *dev, int idle)
+{
+       struct timeval now;
+       int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C);
+
+       ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
+                             disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
+                             ENE_CIR_SAMPLE_OVERFLOW);
+       dev->idle = idle;
+
+       /* remember when we have entered the idle mode */
+       if (idle) {
+               do_gettimeofday(&dev->gap_start);
+               return;
+       }
+
+       /* send the gap between keypresses now */
+       do_gettimeofday(&now);
+
+       if (now.tv_sec - dev->gap_start.tv_sec > 16)
+               dev->sample = space(PULSE_MASK);
+       else
+               dev->sample = dev->sample +
+                   space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec))
+                   + space(now.tv_usec - dev->gap_start.tv_usec);
+
+       if (abs(dev->sample) > PULSE_MASK)
+               dev->sample = space(PULSE_MASK);
+       send_sample(dev);
+}
+
+/* interrupt handler */
+static irqreturn_t ene_hw_irq(int irq, void *data)
+{
+       u16 hw_value;
+       int i, hw_sample;
+       int space;
+       int buffer_pointer;
+       int irq_status;
+
+       struct ene_device *dev = (struct ene_device *)data;
+       irq_status = ene_hw_irq_status(dev, &buffer_pointer);
+
+       if (!irq_status)
+               return IRQ_NONE;
+
+       /* TODO: only RX for now */
+       if (irq_status == ENE_IRQ_TX)
+               return IRQ_HANDLED;
+
+       for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
+
+               hw_value = ene_hw_read_reg(dev,
+                               ENE_SAMPLE_BUFFER + buffer_pointer + i);
+
+               if (dev->fan_input_inuse) {
+                       /* read high part of the sample */
+                       hw_value |= ene_hw_read_reg(dev,
+                           ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8;
+
+                       /* test for _space_ bit */
+                       space = !(hw_value & ENE_FAN_SMPL_PULS_MSK);
+
+                       /* clear space bit, and other unused bits */
+                       hw_value &= ENE_FAN_VALUE_MASK;
+                       hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN;
+
+               } else {
+                       space = hw_value & ENE_SAMPLE_SPC_MASK;
+                       hw_value &= ENE_SAMPLE_VALUE_MASK;
+                       hw_sample = hw_value * sample_period;
+               }
+
+               /* no more data */
+               if (!(hw_value))
+                       break;
+
+               if (space)
+                       hw_sample *= -1;
+
+               /* overflow sample recieved, handle it */
+
+               if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) {
+
+                       if (dev->idle)
+                               continue;
+
+                       if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP)
+                               update_sample(dev, hw_sample);
+                       else
+                               ene_set_idle(dev, 1);
+
+                       continue;
+               }
+
+               /* normal first sample recieved */
+               if (!dev->fan_input_inuse && dev->idle) {
+                       ene_set_idle(dev, 0);
+
+                       /* discard first recieved value, its random
+                          since its the time signal was off before
+                          first pulse if idle mode is enabled, HW
+                          does that for us */
+
+                       if (!enable_idle)
+                               continue;
+               }
+               update_sample(dev, hw_sample);
+               send_sample(dev);
+       }
+       return IRQ_HANDLED;
+}
+
+static int ene_probe(struct pnp_dev *pnp_dev,
+                    const struct pnp_device_id *dev_id)
+{
+       struct ene_device *dev;
+       struct lirc_driver *lirc_driver;
+       int error = -ENOMEM;
+
+       dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
+
+       if (!dev)
+               goto err1;
+
+       dev->pnp_dev = pnp_dev;
+       pnp_set_drvdata(pnp_dev, dev);
+
+
+       /* prepare lirc interface */
+       error = -ENOMEM;
+       lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+
+       if (!lirc_driver)
+               goto err2;
+
+       dev->lirc_driver = lirc_driver;
+
+       strcpy(lirc_driver->name, ENE_DRIVER_NAME);
+       lirc_driver->minor = -1;
+       lirc_driver->code_length = sizeof(int) * 8;
+       lirc_driver->features = LIRC_CAN_REC_MODE2;
+       lirc_driver->data = dev;
+       lirc_driver->set_use_inc = ene_hw_init;
+       lirc_driver->set_use_dec = ene_hw_deinit;
+       lirc_driver->dev = &pnp_dev->dev;
+       lirc_driver->owner = THIS_MODULE;
+
+       lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+
+       if (!lirc_driver->rbuf)
+               goto err3;
+
+       if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256))
+               goto err4;
+
+       error = -ENODEV;
+       if (lirc_register_driver(lirc_driver))
+               goto err5;
+
+       /* validate resources */
+       if (!pnp_port_valid(pnp_dev, 0) ||
+           pnp_port_len(pnp_dev, 0) < ENE_MAX_IO)
+               goto err6;
+
+       if (!pnp_irq_valid(pnp_dev, 0))
+               goto err6;
+
+       dev->hw_io = pnp_port_start(pnp_dev, 0);
+       dev->irq = pnp_irq(pnp_dev, 0);
+
+       /* claim the resources */
+       error = -EBUSY;
+       if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME))
+               goto err6;
+
+       if (request_irq(dev->irq, ene_hw_irq,
+                       IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
+               goto err7;
+
+       /* detect hardware version and features */
+       error = ene_hw_detect(dev);
+       if (error)
+               goto err8;
+
+       ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n");
+       return 0;
+
+err8:
+       free_irq(dev->irq, dev);
+err7:
+       release_region(dev->hw_io, ENE_MAX_IO);
+err6:
+       lirc_unregister_driver(lirc_driver->minor);
+err5:
+       lirc_buffer_free(lirc_driver->rbuf);
+err4:
+       kfree(lirc_driver->rbuf);
+err3:
+       kfree(lirc_driver);
+err2:
+       kfree(dev);
+err1:
+       return error;
+}
+
+static void ene_remove(struct pnp_dev *pnp_dev)
+{
+       struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+       ene_hw_deinit(dev);
+       free_irq(dev->irq, dev);
+       release_region(dev->hw_io, ENE_MAX_IO);
+       lirc_unregister_driver(dev->lirc_driver->minor);
+       lirc_buffer_free(dev->lirc_driver->rbuf);
+       kfree(dev->lirc_driver);
+       kfree(dev);
+}
+
+#ifdef CONFIG_PM
+
+/* TODO: make 'wake on IR' configurable and add .shutdown */
+/* currently impossible due to lack of kernel support */
+
+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+       struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+       ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE);
+       return 0;
+}
+
+static int ene_resume(struct pnp_dev *pnp_dev)
+{
+       struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+       if (dev->in_use)
+               ene_hw_init(dev);
+
+       ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE);
+       return 0;
+}
+
+#endif
+
+static const struct pnp_device_id ene_ids[] = {
+       {.id = "ENE0100",},
+       {},
+};
+
+static struct pnp_driver ene_driver = {
+       .name = ENE_DRIVER_NAME,
+       .id_table = ene_ids,
+       .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+
+       .probe = ene_probe,
+       .remove = __devexit_p(ene_remove),
+
+#ifdef CONFIG_PM
+       .suspend = ene_suspend,
+       .resume = ene_resume,
+#endif
+};
+
+static int __init ene_init(void)
+{
+       if (sample_period < 5) {
+               ene_printk(KERN_ERR, "sample period must be at\n");
+               ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n");
+               return -EINVAL;
+       }
+       return pnp_register_driver(&ene_driver);
+}
+
+static void ene_exit(void)
+{
+       pnp_unregister_driver(&ene_driver);
+}
+
+module_param(sample_period, int, S_IRUGO);
+MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)");
+
+module_param(enable_idle, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_idle,
+       "Enables turning off signal sampling after long inactivity time; "
+       "if disabled might help detecting input signal (default: enabled)");
+
+module_param(enable_learning, bool, S_IRUGO);
+MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever");
+
+MODULE_DEVICE_TABLE(pnp, ene_ids);
+MODULE_DESCRIPTION
+    ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port");
+MODULE_AUTHOR("Maxim Levitsky");
+MODULE_LICENSE("GPL");
+
+module_init(ene_init);
+module_exit(ene_exit);
diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h
new file mode 100644 (file)
index 0000000..776b693
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@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
+ */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* hardware address */
+#define ENE_STATUS             0        /* hardware status - unused */
+#define ENE_ADDR_HI            1        /* hi byte of register address */
+#define ENE_ADDR_LO            2        /* low byte of register address */
+#define ENE_IO                 3        /* read/write window */
+#define ENE_MAX_IO             4
+
+/* 8 bytes of samples, divided in 2 halfs*/
+#define ENE_SAMPLE_BUFFER      0xF8F0   /* regular sample buffer */
+#define ENE_SAMPLE_SPC_MASK    (1 << 7) /* sample is space */
+#define ENE_SAMPLE_VALUE_MASK  0x7F
+#define ENE_SAMPLE_OVERFLOW    0x7F
+#define ENE_SAMPLES_SIZE       4
+
+/* fan input sample buffer */
+#define ENE_SAMPLE_BUFFER_FAN  0xF8FB   /* this buffer holds high byte of */
+                                        /* each sample of normal buffer */
+
+#define ENE_FAN_SMPL_PULS_MSK  0x8000   /* this bit of combined sample */
+                                        /* if set, says that sample is pulse */
+#define ENE_FAN_VALUE_MASK     0x0FFF   /* mask for valid bits of the value */
+
+/* first firmware register */
+#define ENE_FW1                        0xF8F8
+#define        ENE_FW1_ENABLE          (1 << 0) /* enable fw processing */
+#define ENE_FW1_TXIRQ          (1 << 1) /* TX interrupt pending */
+#define ENE_FW1_WAKE           (1 << 6) /* enable wake from S3 */
+#define ENE_FW1_IRQ            (1 << 7) /* enable interrupt */
+
+/* second firmware register */
+#define ENE_FW2                        0xF8F9
+#define ENE_FW2_BUF_HIGH       (1 << 0) /* which half of the buffer to read */
+#define ENE_FW2_IRQ_CLR                (1 << 2) /* clear this on IRQ */
+#define ENE_FW2_GP40_AS_LEARN  (1 << 4) /* normal input is used as */
+                                        /* learning input */
+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */
+#define ENE_FW2_LEARNING       (1 << 7) /* hardware supports learning and TX */
+
+/* fan as input settings - only if learning capable */
+#define ENE_FAN_AS_IN1         0xFE30   /* fan init reg 1 */
+#define ENE_FAN_AS_IN1_EN      0xCD
+#define ENE_FAN_AS_IN2         0xFE31   /* fan init reg 2 */
+#define ENE_FAN_AS_IN2_EN      0x03
+#define ENE_SAMPLE_PERIOD_FAN   61      /* fan input has fixed sample period */
+
+/* IRQ registers block (for revision B) */
+#define ENEB_IRQ               0xFD09   /* IRQ number */
+#define ENEB_IRQ_UNK1          0xFD17   /* unknown setting = 1 */
+#define ENEB_IRQ_STATUS                0xFD80   /* irq status */
+#define ENEB_IRQ_STATUS_IR     (1 << 5) /* IR irq */
+
+/* IRQ registers block (for revision C,D) */
+#define ENEC_IRQ               0xFE9B   /* new irq settings register */
+#define ENEC_IRQ_MASK          0x0F     /* irq number mask */
+#define ENEC_IRQ_UNK_EN                (1 << 4) /* always enabled */
+#define ENEC_IRQ_STATUS                (1 << 5) /* irq status and ACK */
+
+/* CIR block settings */
+#define ENE_CIR_CONF1          0xFEC0
+#define ENE_CIR_CONF1_ADC_ON   0x7      /* reciever on gpio40 enabled */
+#define ENE_CIR_CONF1_LEARN1   (1 << 3) /* enabled on learning mode */
+#define ENE_CIR_CONF1_TX_ON    0x30     /* enabled on transmit */
+#define ENE_CIR_CONF1_TX_CARR  (1 << 7) /* send TX carrier or not */
+
+#define ENE_CIR_CONF2          0xFEC1   /* unknown setting = 0 */
+#define ENE_CIR_CONF2_LEARN2   (1 << 4) /* set on enable learning */
+#define ENE_CIR_CONF2_GPIO40DIS        (1 << 5) /* disable normal input via gpio40 */
+
+#define ENE_CIR_SAMPLE_PERIOD  0xFEC8   /* sample period in us */
+#define ENE_CIR_SAMPLE_OVERFLOW        (1 << 7) /* interrupt on overflows if set */
+
+
+/* transmitter - not implemented yet */
+/* KB3926C and higher */
+/* transmission is very similiar to recieving, a byte is written to */
+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */
+/* sample period is fixed*/
+
+
+/* transmitter ports */
+#define ENE_TX_PORT1           0xFC01   /* this enables one or both */
+#define ENE_TX_PORT1_EN                (1 << 5) /* TX ports */
+#define ENE_TX_PORT2           0xFC08
+#define ENE_TX_PORT2_EN                (1 << 1)
+
+#define ENE_TX_INPUT           0xFEC9   /* next byte to transmit */
+#define ENE_TX_SPC_MASK                (1 << 7) /* Transmitted sample is space */
+#define ENE_TX_UNK1            0xFECB   /* set to 0x63 */
+#define ENE_TX_SMPL_PERIOD     50       /* transmit sample period */
+
+
+#define ENE_TX_CARRIER         0xFECE   /* TX carrier * 2 (khz) */
+#define ENE_TX_CARRIER_UNKBIT  0x80     /* This bit set on transmit */
+#define ENE_TX_CARRIER_LOW     0xFECF   /* TX carrier / 2 */
+
+/* Hardware versions */
+#define ENE_HW_VERSION         0xFF00   /* hardware revision */
+#define ENE_HW_UNK             0xFF1D
+#define ENE_HW_UNK_CLR         (1 << 2)
+#define ENE_HW_VER_MAJOR       0xFF1E   /* chip version */
+#define ENE_HW_VER_MINOR       0xFF1F
+#define ENE_HW_VER_OLD         0xFD00
+
+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
+
+#define ENE_DRIVER_NAME                "enecir"
+#define ENE_MAXGAP             250000   /* this is amount of time we wait
+                                        before turning the sampler, chosen
+                                        arbitry */
+
+#define space(len)            (-(len))  /* add a space */
+
+/* software defines */
+#define ENE_IRQ_RX             1
+#define ENE_IRQ_TX             2
+
+#define  ENE_HW_B              1       /* 3926B */
+#define  ENE_HW_C              2       /* 3926C */
+#define  ENE_HW_D              3       /* 3926D */
+
+#define ene_printk(level, text, ...) \
+       printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+
+struct ene_device {
+       struct pnp_dev *pnp_dev;
+       struct lirc_driver *lirc_driver;
+
+       /* hw settings */
+       unsigned long hw_io;
+       int irq;
+
+       int hw_revision;                        /* hardware revision */
+       int hw_learning_and_tx_capable;         /* learning capable */
+       int hw_gpio40_learning;                 /* gpio40 is learning */
+       int hw_fan_as_normal_input;     /* fan input is used as regular input */
+
+       /* device data */
+       int idle;
+       int fan_input_inuse;
+
+       int sample;
+       int in_use;
+
+       struct timeval gap_start;
+};
diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c
new file mode 100644 (file)
index 0000000..6df2c0e
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * lirc_i2c.c
+ *
+ * i2c IR driver for the onboard IR port on many TV tuner cards, including:
+ *  -Flavors of the Hauppauge PVR-150/250/350
+ *  -Hauppauge HVR-1300
+ *  -PixelView (BT878P+W/FM)
+ *  -KNC ONE TV Station/Anubis Typhoon TView Tuner
+ *  -Asus TV-Box and Creative/VisionTek BreakOut-Box
+ *  -Leadtek Winfast PVR2000
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ *      Michal Kochanowicz <mkochano@pld.org.pl>
+ *      Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ *      Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ *      Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ *      Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge HVR-1300 by
+ *      Jan Frey (jfrey@gmx.de)
+ *
+ * parts are cut&pasted from the old lirc_haup.c 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <media/lirc_dev.h>
+
+struct IR {
+       struct lirc_driver l;
+       struct i2c_client  c;
+       int nextkey;
+       unsigned char b[3];
+       unsigned char bits;
+       unsigned char flag;
+};
+
+#define DEVICE_NAME "lirc_i2c"
+
+/* module parameters */
+static int debug;      /* debug output */
+static int minor = -1; /* minor number */
+
+#define dprintk(fmt, args...)                                          \
+       do {                                                            \
+               if (debug)                                              \
+                       printk(KERN_DEBUG DEVICE_NAME ": " fmt,         \
+                              ## args);                                \
+       } while (0)
+
+static int reverse(int data, int bits)
+{
+       int i;
+       int c;
+
+       for (c = 0, i = 0; i < bits; i++)
+               c |= ((data & (1<<i)) ? 1 : 0) << (bits-1-i);
+
+       return c;
+}
+
+static int add_to_buf_adap(void *data, struct lirc_buffer *buf)
+{
+       struct IR *ir = data;
+       unsigned char keybuf[4];
+
+       keybuf[0] = 0x00;
+       i2c_master_send(&ir->c, keybuf, 1);
+       /* poll IR chip */
+       if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
+               dprintk("read error\n");
+               return -EIO;
+       }
+
+       dprintk("key (0x%02x%02x%02x%02x)\n",
+               keybuf[0], keybuf[1], keybuf[2], keybuf[3]);
+
+       /* key pressed ? */
+       if (keybuf[2] == 0xff)
+               return -ENODATA;
+
+       /* remove repeat bit */
+       keybuf[2] &= 0x7f;
+       keybuf[3] |= 0x80;
+
+       lirc_buffer_write(buf, keybuf);
+       return 0;
+}
+
+static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf)
+{
+       struct IR *ir = data;
+       int rc;
+       unsigned char all, mask;
+       unsigned char key;
+
+       /* compute all valid bits (key code + pressed/release flag) */
+       all = ir->bits | ir->flag;
+
+       /* save IR writable mask bits */
+       mask = i2c_smbus_read_byte(&ir->c) & ~all;
+
+       /* send bit mask */
+       rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask);
+
+       /* receive scan code */
+       rc = i2c_smbus_read_byte(&ir->c);
+
+       if (rc == -1) {
+               dprintk("%s read error\n", ir->c.name);
+               return -EIO;
+       }
+
+       /* drop duplicate polls */
+       if (ir->b[0] == (rc & all))
+               return -ENODATA;
+
+       ir->b[0] = rc & all;
+
+       dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits,
+               (rc & ir->flag) ? "released" : "pressed");
+
+       /* ignore released buttons */
+       if (rc & ir->flag)
+               return -ENODATA;
+
+       /* set valid key code */
+       key  = rc & ir->bits;
+       lirc_buffer_write(buf, &key);
+       return 0;
+}
+
+/* common for Hauppauge IR receivers */
+static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf,
+               unsigned char *keybuf, int size, int offset)
+{
+       struct IR *ir = data;
+       __u16 code;
+       unsigned char codes[2];
+       int ret;
+
+       /* poll IR chip */
+       ret = i2c_master_recv(&ir->c, keybuf, size);
+       if (ret == size) {
+               ir->b[0] = keybuf[offset];
+               ir->b[1] = keybuf[offset+1];
+               ir->b[2] = keybuf[offset+2];
+               if (ir->b[0] != 0x00 && ir->b[1] != 0x00)
+                       dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+       } else {
+               dprintk("read error (ret=%d)\n", ret);
+               /* keep last successful read buffer */
+       }
+
+       /* key pressed ? */
+       if ((ir->b[0] & 0x80) == 0)
+               return -ENODATA;
+
+       /* look what we have */
+       code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2);
+
+       codes[0] = (code >> 8) & 0xff;
+       codes[1] = code & 0xff;
+
+       /* return it */
+       dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]);
+       lirc_buffer_write(buf, codes);
+       return 0;
+}
+
+/* specific for the Hauppauge PVR150 IR receiver */
+static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf)
+{
+       unsigned char keybuf[6];
+       /* fetch 6 bytes, first relevant is at offset 3 */
+       return add_to_buf_haup_common(data, buf, keybuf, 6, 3);
+}
+
+/* used for all Hauppauge IR receivers but the PVR150 */
+static int add_to_buf_haup(void *data, struct lirc_buffer *buf)
+{
+       unsigned char keybuf[3];
+       /* fetch 3 bytes, first relevant is at offset 0 */
+       return add_to_buf_haup_common(data, buf, keybuf, 3, 0);
+}
+
+
+static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf)
+{
+       struct IR *ir = data;
+       unsigned char key;
+       s32 flags;
+       s32 code;
+
+       /* poll IR chip */
+       flags = i2c_smbus_read_byte_data(&ir->c, 0x10);
+       if (-1 == flags) {
+               dprintk("read error\n");
+               return -ENODATA;
+       }
+       /* key pressed ? */
+       if (0 == (flags & 0x80))
+               return -ENODATA;
+
+       /* read actual key code */
+       code = i2c_smbus_read_byte_data(&ir->c, 0x00);
+       if (-1 == code) {
+               dprintk("read error\n");
+               return -ENODATA;
+       }
+
+       key = code & 0xFF;
+
+       dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF);
+
+       /* return it */
+       lirc_buffer_write(buf, &key);
+       return 0;
+}
+
+static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf)
+{
+       struct IR *ir = data;
+       unsigned char key;
+
+       /* poll IR chip */
+       if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+               dprintk("read error\n");
+               return -1;
+       }
+       dprintk("key %02x\n", key);
+
+       /* return it */
+       lirc_buffer_write(buf, &key);
+       return 0;
+}
+
+static int add_to_buf_pv951(void *data, struct lirc_buffer *buf)
+{
+       struct IR *ir = data;
+       unsigned char key;
+       unsigned char codes[4];
+
+       /* poll IR chip */
+       if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+               dprintk("read error\n");
+               return -ENODATA;
+       }
+       /* ignore 0xaa */
+       if (key == 0xaa)
+               return -ENODATA;
+       dprintk("key %02x\n", key);
+
+       codes[0] = 0x61;
+       codes[1] = 0xD6;
+       codes[2] = reverse(key, 8);
+       codes[3] = (~codes[2])&0xff;
+
+       lirc_buffer_write(buf, codes);
+       return 0;
+}
+
+static int add_to_buf_knc1(void *data, struct lirc_buffer *buf)
+{
+       static unsigned char last_key = 0xFF;
+       struct IR *ir = data;
+       unsigned char key;
+
+       /* poll IR chip */
+       if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+               dprintk("read error\n");
+               return -ENODATA;
+       }
+
+       /*
+        * it seems that 0xFE indicates that a button is still held
+        * down, while 0xFF indicates that no button is held
+        * down. 0xFE sequences are sometimes interrupted by 0xFF
+        */
+
+       dprintk("key %02x\n", key);
+
+       if (key == 0xFF)
+               return -ENODATA;
+
+       if (key == 0xFE)
+               key = last_key;
+
+       last_key = key;
+       lirc_buffer_write(buf, &key);
+
+       return 0;
+}
+
+static int set_use_inc(void *data)
+{
+       struct IR *ir = data;
+
+       dprintk("%s called\n", __func__);
+
+       /* lock bttv in memory while /dev/lirc is in use  */
+       i2c_use_client(&ir->c);
+
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       struct IR *ir = data;
+
+       dprintk("%s called\n", __func__);
+
+       i2c_release_client(&ir->c);
+}
+
+static struct lirc_driver lirc_template = {
+       .name           = "lirc_i2c",
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .dev            = NULL,
+       .owner          = THIS_MODULE,
+};
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
+static int ir_remove(struct i2c_client *client);
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+
+static const struct i2c_device_id ir_receiver_id[] = {
+       /* Generic entry for any IR receiver */
+       { "ir_video", 0 },
+       /* IR device specific entries could be added here */
+       { }
+};
+
+static struct i2c_driver driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "i2c ir driver",
+       },
+       .probe          = ir_probe,
+       .remove         = ir_remove,
+       .id_table       = ir_receiver_id,
+       .command        = ir_command,
+};
+
+static void pcf_probe(struct i2c_client *client, struct IR *ir)
+{
+       int ret1, ret2, ret3, ret4;
+
+       ret1 = i2c_smbus_write_byte(client, 0xff);
+       ret2 = i2c_smbus_read_byte(client);
+       ret3 = i2c_smbus_write_byte(client, 0x00);
+       ret4 = i2c_smbus_read_byte(client);
+
+       /* in the Asus TV-Box: bit 1-0 */
+       if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) {
+               ir->bits = (unsigned char) ~0x07;
+               ir->flag = 0x04;
+       /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */
+       } else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) {
+               ir->bits = (unsigned char) ~0xe0;
+               ir->flag = 0x20;
+       }
+
+       return;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct IR *ir;
+       struct i2c_adapter *adap = client->adapter;
+       unsigned short addr = client->addr;
+       int retval;
+
+       ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+       if (!ir)
+               return -ENOMEM;
+       memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+       memcpy(&ir->c, client, sizeof(struct i2c_client));
+
+       i2c_set_clientdata(client, ir);
+       ir->l.data    = ir;
+       ir->l.minor   = minor;
+       ir->l.sample_rate = 10;
+       ir->l.dev     = &ir->c.dev;
+       ir->nextkey   = -1;
+
+       switch (addr) {
+       case 0x64:
+               strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE);
+               ir->l.code_length = 8;
+               ir->l.add_to_buf = add_to_buf_pixelview;
+               break;
+       case 0x4b:
+               strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE);
+               ir->l.code_length = 32;
+               ir->l.add_to_buf = add_to_buf_pv951;
+               break;
+       case 0x71:
+               if (adap->id == I2C_HW_B_CX2388x)
+                       strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE);
+               else /* bt8xx or cx2341x */
+                       /*
+                        * The PVR150 IR receiver uses the same protocol as
+                        * other Hauppauge cards, but the data flow is
+                        * different, so we need to deal with it by its own.
+                        */
+                       strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE);
+               ir->l.code_length = 13;
+               ir->l.add_to_buf = add_to_buf_haup_pvr150;
+               break;
+       case 0x6b:
+               strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE);
+               ir->l.code_length = 32;
+               ir->l.add_to_buf = add_to_buf_adap;
+               break;
+       case 0x18:
+       case 0x1a:
+               if (adap->id == I2C_HW_B_CX2388x) {
+                       strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE);
+                       ir->l.code_length = 8;
+                       ir->l.add_to_buf = add_to_buf_pvr2000;
+               } else { /* bt8xx or cx2341x */
+                       strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE);
+                       ir->l.code_length = 13;
+                       ir->l.add_to_buf = add_to_buf_haup;
+               }
+               break;
+       case 0x30:
+               strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE);
+               ir->l.code_length = 8;
+               ir->l.add_to_buf = add_to_buf_knc1;
+               break;
+       case 0x21:
+       case 0x23:
+               pcf_probe(client, ir);
+               strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE);
+               ir->l.code_length = 8;
+               ir->l.add_to_buf = add_to_buf_pcf8574;
+               break;
+       default:
+               /* shouldn't happen */
+               printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr);
+               kfree(ir);
+               return -EINVAL;
+       }
+       printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n",
+              adap->id, addr, ir->c.name);
+
+       retval = lirc_register_driver(&ir->l);
+
+       if (retval < 0) {
+               printk(KERN_ERR "lirc_i2c: failed to register driver!\n");
+               kfree(ir);
+               return retval;
+       }
+
+       ir->l.minor = retval;
+
+       return 0;
+}
+
+static int ir_remove(struct i2c_client *client)
+{
+       struct IR *ir = i2c_get_clientdata(client);
+
+       /* unregister device */
+       lirc_unregister_driver(ir->l.minor);
+
+       /* free memory */
+       kfree(ir);
+       return 0;
+}
+
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+       /* nothing */
+       return 0;
+}
+
+static int __init lirc_i2c_init(void)
+{
+       i2c_add_driver(&driver);
+       return 0;
+}
+
+static void __exit lirc_i2c_exit(void)
+{
+       i2c_del_driver(&driver);
+}
+
+MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and "
+                  "Pixelview cards (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+             "Ulrich Mueller, Stefan Jahn, Jerome Brock");
+MODULE_LICENSE("GPL");
+
+module_param(minor, int, S_IRUGO);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_init(lirc_i2c_init);
+module_exit(lirc_i2c_exit);
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c
new file mode 100644 (file)
index 0000000..bce600e
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * lirc_igorplugusb - USB remote support for LIRC
+ *
+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
+ *
+ * The device can only record bursts of up to 36 pulses/spaces.
+ * Works fine with RC5. Longer commands lead to device buffer overrun.
+ * (Maybe a better firmware or a microcontroller with more ram can help?)
+ *
+ * Version 0.1  [beta status]
+ *
+ * Copyright (C) 2004 Jan M. Hochstein
+ *     <hochstein@algo.informatik.tu-darmstadt.de>
+ *
+ * This driver was derived from:
+ *   Paul Miller <pmiller9@users.sourceforge.net>
+ *      "lirc_atiusb" module
+ *   Vladimir Dergachev <volodya@minspring.com>'s 2002
+ *      "USB ATI Remote support" (input device)
+ *   Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002
+ *      "USB StreamZap remote driver" (LIRC)
+ *   Artur Lipowski <alipowski@kki.net.pl>'s 2002
+ *      "lirc_dev" and "lirc_gpio" LIRC modules
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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/kernel.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+/* module identification */
+#define DRIVER_VERSION         "0.1"
+#define DRIVER_AUTHOR          \
+       "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
+#define DRIVER_DESC            "USB remote driver for LIRC"
+#define DRIVER_NAME            "lirc_igorplugusb"
+
+/* debugging support */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define dprintk(fmt, args...)                                  \
+       do {                                                    \
+               if (debug)                                      \
+                       printk(KERN_DEBUG fmt, ## args);        \
+       } while (0)
+
+/* One mode2 pulse/space has 4 bytes. */
+#define CODE_LENGTH         sizeof(int)
+
+/* Igor's firmware cannot record bursts longer than 36. */
+#define DEVICE_BUFLEN     36
+
+/*
+ * Header at the beginning of the device's buffer:
+ *     unsigned char data_length
+ *     unsigned char data_start    (!=0 means ring-buffer overrun)
+ *     unsigned char counter       (incremented by each burst)
+ */
+#define DEVICE_HEADERLEN       3
+
+/* This is for the gap */
+#define ADDITIONAL_LIRC_BYTES   2
+
+/* times to poll per second */
+#define SAMPLE_RATE         100
+static int sample_rate = SAMPLE_RATE;
+
+
+/**** Igor's USB Request Codes */
+
+#define SET_INFRABUFFER_EMPTY   1
+/**
+ * Params: none
+ * Answer: empty
+ */
+
+#define GET_INFRACODE     2
+/**
+ * Params:
+ *   wValue: offset to begin reading infra buffer
+ *
+ * Answer: infra data
+ */
+
+#define SET_DATAPORT_DIRECTION  3
+/**
+ * Params:
+ *   wValue: (byte) 1 bit for each data port pin (0=in, 1=out)
+ *
+ * Answer: empty
+ */
+
+#define GET_DATAPORT_DIRECTION  4
+/**
+ * Params: none
+ *
+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out)
+ */
+
+#define SET_OUT_DATAPORT       5
+/**
+ * Params:
+ *   wValue: byte to write to output data port
+ *
+ * Answer: empty
+ */
+
+#define GET_OUT_DATAPORT       6
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from output data port
+ */
+
+#define GET_IN_DATAPORT         7
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from input data port
+ */
+
+#define READ_EEPROM         8
+/**
+ * Params:
+ *   wValue: offset to begin reading EEPROM
+ *
+ * Answer: EEPROM bytes
+ */
+
+#define WRITE_EEPROM       9
+/**
+ * Params:
+ *   wValue: offset to EEPROM byte
+ *   wIndex: byte to write
+ *
+ * Answer: empty
+ */
+
+#define SEND_RS232           10
+/**
+ * Params:
+ *   wValue: byte to send
+ *
+ * Answer: empty
+ */
+
+#define RECV_RS232           11
+/**
+ * Params: none
+ *
+ * Answer: byte received
+ */
+
+#define SET_RS232_BAUD   12
+/**
+ * Params:
+ *   wValue: byte to write to UART bit rate register (UBRR)
+ *
+ * Answer: empty
+ */
+
+#define GET_RS232_BAUD   13
+/**
+ * Params: none
+ *
+ * Answer: byte read from UART bit rate register (UBRR)
+ */
+
+
+/* data structure for each usb remote */
+struct igorplug {
+
+       /* usb */
+       struct usb_device *usbdev;
+       struct urb *urb_in;
+       int devnum;
+
+       unsigned char *buf_in;
+       unsigned int len_in;
+       int in_space;
+       struct timeval last_time;
+
+       dma_addr_t dma_in;
+
+       /* lirc */
+       struct lirc_driver *d;
+
+       /* handle sending (init strings) */
+       int send_flags;
+       wait_queue_head_t wait_out;
+};
+
+static int unregister_from_lirc(struct igorplug *ir)
+{
+       struct lirc_driver *d = ir->d;
+       int devnum;
+
+       if (!ir->d)
+               return -EINVAL;
+
+       devnum = ir->devnum;
+       dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum);
+
+       lirc_unregister_driver(d->minor);
+
+       printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum);
+
+       kfree(d);
+       ir->d = NULL;
+       kfree(ir);
+       return 0;
+}
+
+static int set_use_inc(void *data)
+{
+       struct igorplug *ir = data;
+
+       if (!ir) {
+               printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
+               return -EIO;
+       }
+       dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
+
+       if (!ir->usbdev)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       struct igorplug *ir = data;
+
+       if (!ir) {
+               printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
+               return;
+       }
+       dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
+}
+
+
+/**
+ * Called in user context.
+ * return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ */
+static int usb_remote_poll(void *data, struct lirc_buffer *buf)
+{
+       int ret;
+       struct igorplug *ir = (struct igorplug *)data;
+
+       if (!ir->usbdev)  /* Has the device been removed? */
+               return -ENODEV;
+
+       memset(ir->buf_in, 0, ir->len_in);
+
+       ret = usb_control_msg(
+             ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+             GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN,
+             0/* offset */, /*unused*/0,
+             ir->buf_in, ir->len_in,
+             /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+       if (ret > 0) {
+               int i = DEVICE_HEADERLEN;
+               int code, timediff;
+               struct timeval now;
+
+               if (ret <= 1)  /* ACK packet has 1 byte --> ignore */
+                       return -ENODATA;
+
+               dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
+                       ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
+
+               if (ir->buf_in[2] != 0) {
+                       printk(DRIVER_NAME "[%d]: Device buffer overrun.\n",
+                               ir->devnum);
+                       /* start at earliest byte */
+                       i = DEVICE_HEADERLEN + ir->buf_in[2];
+                       /* where are we now? space, gap or pulse? */
+               }
+
+               do_gettimeofday(&now);
+               timediff = now.tv_sec - ir->last_time.tv_sec;
+               if (timediff + 1 > PULSE_MASK / 1000000)
+                       timediff = PULSE_MASK;
+               else {
+                       timediff *= 1000000;
+                       timediff += now.tv_usec - ir->last_time.tv_usec;
+               }
+               ir->last_time.tv_sec = now.tv_sec;
+               ir->last_time.tv_usec = now.tv_usec;
+
+               /* create leading gap  */
+               code = timediff;
+               lirc_buffer_write(buf, (unsigned char *)&code);
+               ir->in_space = 1;   /* next comes a pulse */
+
+               /* MODE2: pulse/space (PULSE_BIT) in 1us units */
+
+               while (i < ret) {
+                       /* 1 Igor-tick = 85.333333 us */
+                       code = (unsigned int)ir->buf_in[i] * 85
+                               + (unsigned int)ir->buf_in[i] / 3;
+                       if (ir->in_space)
+                               code |= PULSE_BIT;
+                       lirc_buffer_write(buf, (unsigned char *)&code);
+                       /* 1 chunk = CODE_LENGTH bytes */
+                       ir->in_space ^= 1;
+                       ++i;
+               }
+
+               ret = usb_control_msg(
+                     ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+                     SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+                     /*unused*/0, /*unused*/0,
+                     /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+                     /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+               if (ret < 0)
+                       printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: "
+                              "error %d\n", ir->devnum, ret);
+               return 0;
+       } else if (ret < 0)
+               printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n",
+                       ir->devnum, ret);
+
+       return -ENODATA;
+}
+
+
+
+static int usb_remote_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct usb_device *dev = NULL;
+       struct usb_host_interface *idesc = NULL;
+       struct usb_host_endpoint *ep_ctl2;
+       struct igorplug *ir = NULL;
+       struct lirc_driver *driver = NULL;
+       int devnum, pipe, maxp;
+       int minor = 0;
+       char buf[63], name[128] = "";
+       int mem_failure = 0;
+       int ret;
+
+       dprintk(DRIVER_NAME ": usb probe called.\n");
+
+       dev = interface_to_usbdev(intf);
+
+       idesc = intf->cur_altsetting;
+
+       if (idesc->desc.bNumEndpoints != 1)
+               return -ENODEV;
+       ep_ctl2 = idesc->endpoint;
+       if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+           != USB_DIR_IN)
+           || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+           != USB_ENDPOINT_XFER_CONTROL)
+               return -ENODEV;
+       pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress);
+       devnum = dev->devnum;
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n",
+               devnum, CODE_LENGTH, maxp);
+
+
+       mem_failure = 0;
+       ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
+       if (!ir) {
+               mem_failure = 1;
+               goto mem_failure_switch;
+       }
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver) {
+               mem_failure = 2;
+               goto mem_failure_switch;
+       }
+
+       ir->buf_in = usb_alloc_coherent(dev,
+                             DEVICE_BUFLEN+DEVICE_HEADERLEN,
+                             GFP_ATOMIC, &ir->dma_in);
+       if (!ir->buf_in) {
+               mem_failure = 3;
+               goto mem_failure_switch;
+       }
+
+       strcpy(driver->name, DRIVER_NAME " ");
+       driver->minor = -1;
+       driver->code_length = CODE_LENGTH * 8; /* in bits */
+       driver->features = LIRC_CAN_REC_MODE2;
+       driver->data = ir;
+       driver->chunk_size = CODE_LENGTH;
+       driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES;
+       driver->set_use_inc = &set_use_inc;
+       driver->set_use_dec = &set_use_dec;
+       driver->sample_rate = sample_rate;    /* per second */
+       driver->add_to_buf = &usb_remote_poll;
+       driver->dev = &intf->dev;
+       driver->owner = THIS_MODULE;
+
+       init_waitqueue_head(&ir->wait_out);
+
+       minor = lirc_register_driver(driver);
+       if (minor < 0)
+               mem_failure = 9;
+
+mem_failure_switch:
+
+       switch (mem_failure) {
+       case 9:
+               usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+                       ir->buf_in, ir->dma_in);
+       case 3:
+               kfree(driver);
+       case 2:
+               kfree(ir);
+       case 1:
+               printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n",
+                       devnum, mem_failure);
+               return -ENOMEM;
+       }
+
+       driver->minor = minor;
+       ir->d = driver;
+       ir->devnum = devnum;
+       ir->usbdev = dev;
+       ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+       ir->in_space = 1; /* First mode2 event is a space. */
+       do_gettimeofday(&ir->last_time);
+
+       if (dev->descriptor.iManufacturer
+           && usb_string(dev, dev->descriptor.iManufacturer,
+                         buf, sizeof(buf)) > 0)
+               strlcpy(name, buf, sizeof(name));
+       if (dev->descriptor.iProduct
+           && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0)
+               snprintf(name + strlen(name), sizeof(name) - strlen(name),
+                        " %s", buf);
+       printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name,
+              dev->bus->busnum, devnum);
+
+       /* clear device buffer */
+       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+               SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+               /*unused*/0, /*unused*/0,
+               /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+               /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+       if (ret < 0)
+               printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
+                       devnum, ret);
+
+       usb_set_intfdata(intf, ir);
+       return 0;
+}
+
+
+static void usb_remote_disconnect(struct usb_interface *intf)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct igorplug *ir = usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
+
+       if (!ir || !ir->d)
+               return;
+
+       ir->usbdev = NULL;
+       wake_up_all(&ir->wait_out);
+
+       usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+       unregister_from_lirc(ir);
+}
+
+static struct usb_device_id usb_remote_id_table[] = {
+       /* Igor Plug USB (Atmel's Manufact. ID) */
+       { USB_DEVICE(0x03eb, 0x0002) },
+
+       /* Terminating entry */
+       { }
+};
+
+static struct usb_driver usb_remote_driver = {
+       .name =         DRIVER_NAME,
+       .probe =        usb_remote_probe,
+       .disconnect =   usb_remote_disconnect,
+       .id_table =     usb_remote_id_table
+};
+
+static int __init usb_remote_init(void)
+{
+       int i;
+
+       printk(KERN_INFO "\n"
+              DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n");
+       printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n");
+       dprintk(DRIVER_NAME ": debug mode enabled\n");
+
+       i = usb_register(&usb_remote_driver);
+       if (i < 0) {
+               printk(DRIVER_NAME ": usb register failed, result = %d\n", i);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit usb_remote_exit(void)
+{
+       usb_deregister(&usb_remote_driver);
+}
+
+module_init(usb_remote_init);
+module_exit(usb_remote_exit);
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, usb_remote_id_table);
+
+module_param(sample_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
+
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c
new file mode 100644 (file)
index 0000000..6649325
--- /dev/null
@@ -0,0 +1,1058 @@
+/*
+ *   lirc_imon.c:  LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
+ *                including the iMON PAD model
+ *
+ *   Copyright(C) 2004  Venky Raju(dev@venky.ws)
+ *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
+ *
+ *   lirc_imon is free software; 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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR     "Venky Raju <dev@venky.ws>"
+#define MOD_DESC       "Driver for SoundGraph iMON MultiMedia IR/Display"
+#define MOD_NAME       "lirc_imon"
+#define MOD_VERSION    "0.8"
+
+#define DISPLAY_MINOR_BASE     144
+#define DEVICE_NAME    "lcd%d"
+
+#define BUF_CHUNK_SIZE 4
+#define BUF_SIZE       128
+
+#define BIT_DURATION   250     /* each bit received is 250us */
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int imon_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id);
+static void imon_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* suspend/resume support */
+static int imon_resume(struct usb_interface *intf);
+static int imon_suspend(struct usb_interface *intf, pm_message_t message);
+
+/* Display file_operations function prototypes */
+static int display_open(struct inode *inode, struct file *file);
+static int display_close(struct inode *inode, struct file *file);
+
+/* VFD write operation */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init imon_init(void);
+static void __exit imon_exit(void);
+
+/*** G L O B A L S ***/
+#define IMON_DATA_BUF_SZ       35
+
+struct imon_context {
+       struct usb_device *usbdev;
+       /* Newer devices have two interfaces */
+       int display;                    /* not all controllers do */
+       int display_isopen;             /* display port has been opened */
+       int ir_isopen;                  /* IR port open */
+       int dev_present;                /* USB device presence */
+       struct mutex ctx_lock;          /* to lock this object */
+       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
+
+       int vfd_proto_6p;               /* some VFD require a 6th packet */
+
+       struct lirc_driver *driver;
+       struct usb_endpoint_descriptor *rx_endpoint;
+       struct usb_endpoint_descriptor *tx_endpoint;
+       struct urb *rx_urb;
+       struct urb *tx_urb;
+       unsigned char usb_rx_buf[8];
+       unsigned char usb_tx_buf[8];
+
+       struct rx_data {
+               int count;              /* length of 0 or 1 sequence */
+               int prev_bit;           /* logic level of sequence */
+               int initial_space;      /* initial space flag */
+       } rx;
+
+       struct tx_t {
+               unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */
+               struct completion finished;     /* wait for write to finish */
+               atomic_t busy;                  /* write in progress */
+               int status;                     /* status of tx completion */
+       } tx;
+};
+
+static const struct file_operations display_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &display_open,
+       .write          = &vfd_write,
+       .release        = &display_close
+};
+
+/*
+ * USB Device ID for iMON USB Control Boards
+ *
+ * The Windows drivers contain 6 different inf files, more or less one for
+ * each new device until the 0x0034-0x0046 devices, which all use the same
+ * driver. Some of the devices in the 34-46 range haven't been definitively
+ * identified yet. Early devices have either a TriGem Computer, Inc. or a
+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
+ * devices use the SoundGraph vendor ID (0x15c2).
+ */
+static struct usb_device_id imon_usb_id_table[] = {
+       /* TriGem iMON (IR only) -- TG_iMON.inf */
+       { USB_DEVICE(0x0aa8, 0x8001) },
+
+       /* SoundGraph iMON (IR only) -- sg_imon.inf */
+       { USB_DEVICE(0x04e8, 0xff30) },
+
+       /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
+       { USB_DEVICE(0x0aa8, 0xffda) },
+
+       /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
+       { USB_DEVICE(0x15c2, 0xffda) },
+
+       {}
+};
+
+/* Some iMON VFD models requires a 6th packet for VFD writes */
+static struct usb_device_id vfd_proto_6p_list[] = {
+       { USB_DEVICE(0x15c2, 0xffda) },
+       {}
+};
+
+/* Some iMON devices have no lcd/vfd, don't set one up */
+static struct usb_device_id ir_only_list[] = {
+       { USB_DEVICE(0x0aa8, 0x8001) },
+       { USB_DEVICE(0x04e8, 0xff30) },
+       {}
+};
+
+/* USB Device data */
+static struct usb_driver imon_driver = {
+       .name           = MOD_NAME,
+       .probe          = imon_probe,
+       .disconnect     = imon_disconnect,
+       .suspend        = imon_suspend,
+       .resume         = imon_resume,
+       .id_table       = imon_usb_id_table,
+};
+
+static struct usb_class_driver imon_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &display_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect(), probing, etc */
+static DEFINE_MUTEX(driver_lock);
+
+static int debug;
+
+/***  M O D U L E   C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+
+static void free_imon_context(struct imon_context *context)
+{
+       struct device *dev = context->driver->dev;
+       usb_free_urb(context->tx_urb);
+       usb_free_urb(context->rx_urb);
+       lirc_buffer_free(context->driver->rbuf);
+       kfree(context->driver->rbuf);
+       kfree(context->driver);
+       kfree(context);
+
+       dev_dbg(dev, "%s: iMON context freed\n", __func__);
+}
+
+static void deregister_from_lirc(struct imon_context *context)
+{
+       int retval;
+       int minor = context->driver->minor;
+
+       retval = lirc_unregister_driver(minor);
+       if (retval)
+               err("%s: unable to deregister from lirc(%d)",
+                       __func__, retval);
+       else
+               printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
+                      "(minor:%d)\n", minor);
+
+}
+
+/**
+ * Called when the Display device (e.g. /dev/lcd0)
+ * is opened by the application.
+ */
+static int display_open(struct inode *inode, struct file *file)
+{
+       struct usb_interface *interface;
+       struct imon_context *context = NULL;
+       int subminor;
+       int retval = 0;
+
+       /* prevent races with disconnect */
+       mutex_lock(&driver_lock);
+
+       subminor = iminor(inode);
+       interface = usb_find_interface(&imon_driver, subminor);
+       if (!interface) {
+               err("%s: could not find interface for minor %d",
+                   __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+       context = usb_get_intfdata(interface);
+
+       if (!context) {
+               err("%s: no context found for minor %d",
+                                       __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->display) {
+               err("%s: display not supported by device", __func__);
+               retval = -ENODEV;
+       } else if (context->display_isopen) {
+               err("%s: display port is already open", __func__);
+               retval = -EBUSY;
+       } else {
+               context->display_isopen = 1;
+               file->private_data = context;
+               dev_info(context->driver->dev, "display port opened\n");
+       }
+
+       mutex_unlock(&context->ctx_lock);
+
+exit:
+       mutex_unlock(&driver_lock);
+       return retval;
+}
+
+/**
+ * Called when the display device (e.g. /dev/lcd0)
+ * is closed by the application.
+ */
+static int display_close(struct inode *inode, struct file *file)
+{
+       struct imon_context *context = NULL;
+       int retval = 0;
+
+       context = (struct imon_context *)file->private_data;
+
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->display) {
+               err("%s: display not supported by device", __func__);
+               retval = -ENODEV;
+       } else if (!context->display_isopen) {
+               err("%s: display is not open", __func__);
+               retval = -EIO;
+       } else {
+               context->display_isopen = 0;
+               dev_info(context->driver->dev, "display port closed\n");
+               if (!context->dev_present && !context->ir_isopen) {
+                       /*
+                        * Device disconnected before close and IR port is not
+                        * open. If IR port is open, context will be deleted by
+                        * ir_close.
+                        */
+                       mutex_unlock(&context->ctx_lock);
+                       free_imon_context(context);
+                       return retval;
+               }
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return retval;
+}
+
+/**
+ * Sends a packet to the device -- this function must be called
+ * with context->ctx_lock held.
+ */
+static int send_packet(struct imon_context *context)
+{
+       unsigned int pipe;
+       int interval = 0;
+       int retval = 0;
+       struct usb_ctrlrequest *control_req = NULL;
+
+       /* Check if we need to use control or interrupt urb */
+       pipe = usb_sndintpipe(context->usbdev,
+                             context->tx_endpoint->bEndpointAddress);
+       interval = context->tx_endpoint->bInterval;
+
+       usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
+                        context->usb_tx_buf,
+                        sizeof(context->usb_tx_buf),
+                        usb_tx_callback, context, interval);
+
+       context->tx_urb->actual_length = 0;
+
+       init_completion(&context->tx.finished);
+       atomic_set(&(context->tx.busy), 1);
+
+       retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
+       if (retval) {
+               atomic_set(&(context->tx.busy), 0);
+               err("%s: error submitting urb(%d)", __func__, retval);
+       } else {
+               /* Wait for transmission to complete (or abort) */
+               mutex_unlock(&context->ctx_lock);
+               retval = wait_for_completion_interruptible(
+                               &context->tx.finished);
+               if (retval)
+                       err("%s: task interrupted", __func__);
+               mutex_lock(&context->ctx_lock);
+
+               retval = context->tx.status;
+               if (retval)
+                       err("%s: packet tx failed (%d)", __func__, retval);
+       }
+
+       kfree(control_req);
+
+       return retval;
+}
+
+/**
+ * Writes data to the VFD.  The iMON VFD is 2x16 characters
+ * and requires data in 5 consecutive USB interrupt packets,
+ * each packet but the last carrying 7 bytes.
+ *
+ * I don't know if the VFD board supports features such as
+ * scrolling, clearing rows, blanking, etc. so at
+ * the caller must provide a full screen of data.  If fewer
+ * than 32 bytes are provided spaces will be appended to
+ * generate a full screen.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos)
+{
+       int i;
+       int offset;
+       int seq;
+       int retval = 0;
+       struct imon_context *context;
+       const unsigned char vfd_packet6[] = {
+               0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
+       int *data_buf;
+
+       context = (struct imon_context *)file->private_data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->dev_present) {
+               err("%s: no iMON device present", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
+               err("%s: invalid payload size", __func__);
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       data_buf = memdup_user(buf, n_bytes);
+       if (IS_ERR(data_buf)) {
+               retval = PTR_ERR(data_buf);
+               goto exit;
+       }
+
+       memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+       /* Pad with spaces */
+       for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
+               context->tx.data_buf[i] = ' ';
+
+       for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
+               context->tx.data_buf[i] = 0xFF;
+
+       offset = 0;
+       seq = 0;
+
+       do {
+               memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
+               context->usb_tx_buf[7] = (unsigned char) seq;
+
+               retval = send_packet(context);
+               if (retval) {
+                       err("%s: send packet failed for packet #%d",
+                                       __func__, seq/2);
+                       goto exit;
+               } else {
+                       seq += 2;
+                       offset += 7;
+               }
+
+       } while (offset < IMON_DATA_BUF_SZ);
+
+       if (context->vfd_proto_6p) {
+               /* Send packet #6 */
+               memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
+               context->usb_tx_buf[7] = (unsigned char) seq;
+               retval = send_packet(context);
+               if (retval)
+                       err("%s: send packet failed for packet #%d",
+                                       __func__, seq/2);
+       }
+
+exit:
+       mutex_unlock(&context->ctx_lock);
+
+       return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+       struct imon_context *context;
+
+       if (!urb)
+               return;
+       context = (struct imon_context *)urb->context;
+       if (!context)
+               return;
+
+       context->tx.status = urb->status;
+
+       /* notify waiters that write has finished */
+       atomic_set(&context->tx.busy, 0);
+       complete(&context->tx.finished);
+
+       return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+       int retval = 0;
+       struct imon_context *context;
+
+       /* prevent races with disconnect */
+       mutex_lock(&driver_lock);
+
+       context = (struct imon_context *)data;
+
+       /* initial IR protocol decode variables */
+       context->rx.count = 0;
+       context->rx.initial_space = 1;
+       context->rx.prev_bit = 0;
+
+       context->ir_isopen = 1;
+       dev_info(context->driver->dev, "IR port opened\n");
+
+       mutex_unlock(&driver_lock);
+       return retval;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+       struct imon_context *context;
+
+       context = (struct imon_context *)data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       context->ir_isopen = 0;
+       dev_info(context->driver->dev, "IR port closed\n");
+
+       if (!context->dev_present) {
+               /*
+                * Device disconnected while IR port was still open. Driver
+                * was not deregistered at disconnect time, so do it now.
+                */
+               deregister_from_lirc(context);
+
+               if (!context->display_isopen) {
+                       mutex_unlock(&context->ctx_lock);
+                       free_imon_context(context);
+                       return;
+               }
+               /*
+                * If display port is open, context will be deleted by
+                * display_close
+                */
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return;
+}
+
+/**
+ * Convert bit count to time duration (in us) and submit
+ * the value to lirc_dev.
+ */
+static void submit_data(struct imon_context *context)
+{
+       unsigned char buf[4];
+       int value = context->rx.count;
+       int i;
+
+       dev_dbg(context->driver->dev, "submitting data to LIRC\n");
+
+       value *= BIT_DURATION;
+       value &= PULSE_MASK;
+       if (context->rx.prev_bit)
+               value |= PULSE_BIT;
+
+       for (i = 0; i < 4; ++i)
+               buf[i] = value>>(i*8);
+
+       lirc_buffer_write(context->driver->rbuf, buf);
+       wake_up(&context->driver->rbuf->wait_poll);
+       return;
+}
+
+static inline int tv2int(const struct timeval *a, const struct timeval *b)
+{
+       int usecs = 0;
+       int sec   = 0;
+
+       if (b->tv_usec > a->tv_usec) {
+               usecs = 1000000;
+               sec--;
+       }
+
+       usecs += a->tv_usec - b->tv_usec;
+
+       sec += a->tv_sec - b->tv_sec;
+       sec *= 1000;
+       usecs /= 1000;
+       sec += usecs;
+
+       if (sec < 0)
+               sec = 1000;
+
+       return sec;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void imon_incoming_packet(struct imon_context *context,
+                                struct urb *urb, int intf)
+{
+       int len = urb->actual_length;
+       unsigned char *buf = urb->transfer_buffer;
+       struct device *dev = context->driver->dev;
+       int octet, bit;
+       unsigned char mask;
+       int i, chunk_num;
+
+       /*
+        * just bail out if no listening IR client
+        */
+       if (!context->ir_isopen)
+               return;
+
+       if (len != 8) {
+               dev_warn(dev, "imon %s: invalid incoming packet "
+                        "size (len = %d, intf%d)\n", __func__, len, intf);
+               return;
+       }
+
+       if (debug) {
+               printk(KERN_INFO "raw packet: ");
+               for (i = 0; i < len; ++i)
+                       printk("%02x ", buf[i]);
+               printk("\n");
+       }
+
+       /*
+        * Translate received data to pulse and space lengths.
+        * Received data is active low, i.e. pulses are 0 and
+        * spaces are 1.
+        *
+        * My original algorithm was essentially similar to
+        * Changwoo Ryu's with the exception that he switched
+        * the incoming bits to active high and also fed an
+        * initial space to LIRC at the start of a new sequence
+        * if the previous bit was a pulse.
+        *
+        * I've decided to adopt his algorithm.
+        */
+
+       if (buf[7] == 1 && context->rx.initial_space) {
+               /* LIRC requires a leading space */
+               context->rx.prev_bit = 0;
+               context->rx.count = 4;
+               submit_data(context);
+               context->rx.count = 0;
+       }
+
+       for (octet = 0; octet < 5; ++octet) {
+               mask = 0x80;
+               for (bit = 0; bit < 8; ++bit) {
+                       int curr_bit = !(buf[octet] & mask);
+                       if (curr_bit != context->rx.prev_bit) {
+                               if (context->rx.count) {
+                                       submit_data(context);
+                                       context->rx.count = 0;
+                               }
+                               context->rx.prev_bit = curr_bit;
+                       }
+                       ++context->rx.count;
+                       mask >>= 1;
+               }
+       }
+
+       if (chunk_num == 10) {
+               if (context->rx.count) {
+                       submit_data(context);
+                       context->rx.count = 0;
+               }
+               context->rx.initial_space = context->rx.prev_bit;
+       }
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+       struct imon_context *context;
+       unsigned char *buf;
+       int len;
+       int intfnum = 0;
+
+       if (!urb)
+               return;
+
+       context = (struct imon_context *)urb->context;
+       if (!context)
+               return;
+
+       buf = urb->transfer_buffer;
+       len = urb->actual_length;
+
+       switch (urb->status) {
+       case -ENOENT:           /* usbcore unlink successful! */
+               return;
+
+       case 0:
+               imon_incoming_packet(context, urb, intfnum);
+               break;
+
+       default:
+               dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
+                        __func__, urb->status);
+               break;
+       }
+
+       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+       return;
+}
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int imon_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id)
+{
+       struct usb_device *usbdev = NULL;
+       struct usb_host_interface *iface_desc = NULL;
+       struct usb_endpoint_descriptor *rx_endpoint = NULL;
+       struct usb_endpoint_descriptor *tx_endpoint = NULL;
+       struct urb *rx_urb = NULL;
+       struct urb *tx_urb = NULL;
+       struct lirc_driver *driver = NULL;
+       struct lirc_buffer *rbuf = NULL;
+       struct device *dev = &interface->dev;
+       int ifnum;
+       int lirc_minor = 0;
+       int num_endpts;
+       int retval = 0;
+       int display_ep_found = 0;
+       int ir_ep_found = 0;
+       int alloc_status = 0;
+       int vfd_proto_6p = 0;
+       int code_length;
+       struct imon_context *context = NULL;
+       int i;
+       u16 vendor, product;
+
+       context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
+       if (!context) {
+               err("%s: kzalloc failed for context", __func__);
+               alloc_status = 1;
+               goto alloc_status_switch;
+       }
+
+       /*
+        * Try to auto-detect the type of display if the user hasn't set
+        * it by hand via the display_type modparam. Default is VFD.
+        */
+       if (usb_match_id(interface, ir_only_list))
+               context->display = 0;
+       else
+               context->display = 1;
+
+       code_length = BUF_CHUNK_SIZE * 8;
+
+       usbdev     = usb_get_dev(interface_to_usbdev(interface));
+       iface_desc = interface->cur_altsetting;
+       num_endpts = iface_desc->desc.bNumEndpoints;
+       ifnum      = iface_desc->desc.bInterfaceNumber;
+       vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
+       product    = le16_to_cpu(usbdev->descriptor.idProduct);
+
+       dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
+               __func__, vendor, product, ifnum);
+
+       /* prevent races probing devices w/multiple interfaces */
+       mutex_lock(&driver_lock);
+
+       /*
+        * Scan the endpoint list and set:
+        *      first input endpoint = IR endpoint
+        *      first output endpoint = display endpoint
+        */
+       for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
+               struct usb_endpoint_descriptor *ep;
+               int ep_dir;
+               int ep_type;
+               ep = &iface_desc->endpoint[i].desc;
+               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (!ir_ep_found &&
+                       ep_dir == USB_DIR_IN &&
+                       ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       rx_endpoint = ep;
+                       ir_ep_found = 1;
+                       dev_dbg(dev, "%s: found IR endpoint\n", __func__);
+
+               } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
+                          ep_type == USB_ENDPOINT_XFER_INT) {
+                       tx_endpoint = ep;
+                       display_ep_found = 1;
+                       dev_dbg(dev, "%s: found display endpoint\n", __func__);
+               }
+       }
+
+       /*
+        * Some iMON receivers have no display. Unfortunately, it seems
+        * that SoundGraph recycles device IDs between devices both with
+        * and without... :\
+        */
+       if (context->display == 0) {
+               display_ep_found = 0;
+               dev_dbg(dev, "%s: device has no display\n", __func__);
+       }
+
+       /* Input endpoint is mandatory */
+       if (!ir_ep_found) {
+               err("%s: no valid input (IR) endpoint found.", __func__);
+               retval = -ENODEV;
+               alloc_status = 2;
+               goto alloc_status_switch;
+       }
+
+       /* Determine if display requires 6 packets */
+       if (display_ep_found) {
+               if (usb_match_id(interface, vfd_proto_6p_list))
+                       vfd_proto_6p = 1;
+
+               dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
+                       __func__, vfd_proto_6p);
+       }
+
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver) {
+               err("%s: kzalloc failed for lirc_driver", __func__);
+               alloc_status = 2;
+               goto alloc_status_switch;
+       }
+       rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!rbuf) {
+               err("%s: kmalloc failed for lirc_buffer", __func__);
+               alloc_status = 3;
+               goto alloc_status_switch;
+       }
+       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+               err("%s: lirc_buffer_init failed", __func__);
+               alloc_status = 4;
+               goto alloc_status_switch;
+       }
+       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rx_urb) {
+               err("%s: usb_alloc_urb failed for IR urb", __func__);
+               alloc_status = 5;
+               goto alloc_status_switch;
+       }
+       tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!tx_urb) {
+               err("%s: usb_alloc_urb failed for display urb",
+                   __func__);
+               alloc_status = 6;
+               goto alloc_status_switch;
+       }
+
+       mutex_init(&context->ctx_lock);
+       context->vfd_proto_6p = vfd_proto_6p;
+
+       strcpy(driver->name, MOD_NAME);
+       driver->minor = -1;
+       driver->code_length = sizeof(int) * 8;
+       driver->sample_rate = 0;
+       driver->features = LIRC_CAN_REC_MODE2;
+       driver->data = context;
+       driver->rbuf = rbuf;
+       driver->set_use_inc = ir_open;
+       driver->set_use_dec = ir_close;
+       driver->dev = &interface->dev;
+       driver->owner = THIS_MODULE;
+
+       mutex_lock(&context->ctx_lock);
+
+       context->driver = driver;
+       /* start out in keyboard mode */
+
+       lirc_minor = lirc_register_driver(driver);
+       if (lirc_minor < 0) {
+               err("%s: lirc_register_driver failed", __func__);
+               alloc_status = 7;
+               goto alloc_status_switch;
+       } else
+               dev_info(dev, "Registered iMON driver "
+                        "(lirc minor: %d)\n", lirc_minor);
+
+       /* Needed while unregistering! */
+       driver->minor = lirc_minor;
+
+       context->usbdev = usbdev;
+       context->dev_present = 1;
+       context->rx_endpoint = rx_endpoint;
+       context->rx_urb = rx_urb;
+
+       /*
+        * tx is used to send characters to lcd/vfd, associate RF
+        * remotes, set IR protocol, and maybe more...
+        */
+       context->tx_endpoint = tx_endpoint;
+       context->tx_urb = tx_urb;
+
+       if (display_ep_found)
+               context->display = 1;
+
+       usb_fill_int_urb(context->rx_urb, context->usbdev,
+               usb_rcvintpipe(context->usbdev,
+                       context->rx_endpoint->bEndpointAddress),
+               context->usb_rx_buf, sizeof(context->usb_rx_buf),
+               usb_rx_callback, context,
+               context->rx_endpoint->bInterval);
+
+       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+       if (retval) {
+               err("%s: usb_submit_urb failed for intf0 (%d)",
+                   __func__, retval);
+               mutex_unlock(&context->ctx_lock);
+               goto exit;
+       }
+
+       usb_set_intfdata(interface, context);
+
+       if (context->display && ifnum == 0) {
+               dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
+                       __func__);
+
+               if (usb_register_dev(interface, &imon_class)) {
+                       /* Not a fatal error, so ignore */
+                       dev_info(dev, "%s: could not get a minor number for "
+                                "display\n", __func__);
+               }
+       }
+
+       dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
+                "usb<%d:%d> initialized\n", vendor, product, ifnum,
+                usbdev->bus->busnum, usbdev->devnum);
+
+alloc_status_switch:
+       mutex_unlock(&context->ctx_lock);
+
+       switch (alloc_status) {
+       case 7:
+               usb_free_urb(tx_urb);
+       case 6:
+               usb_free_urb(rx_urb);
+       case 5:
+               if (rbuf)
+                       lirc_buffer_free(rbuf);
+       case 4:
+               kfree(rbuf);
+       case 3:
+               kfree(driver);
+       case 2:
+               kfree(context);
+               context = NULL;
+       case 1:
+               if (retval != -ENODEV)
+                       retval = -ENOMEM;
+               break;
+       case 0:
+               retval = 0;
+       }
+
+exit:
+       mutex_unlock(&driver_lock);
+
+       return retval;
+}
+
+/**
+ * Callback function for USB core API: disconnect
+ */
+static void imon_disconnect(struct usb_interface *interface)
+{
+       struct imon_context *context;
+       int ifnum;
+
+       /* prevent races with ir_open()/display_open() */
+       mutex_lock(&driver_lock);
+
+       context = usb_get_intfdata(interface);
+       ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+       mutex_lock(&context->ctx_lock);
+
+       usb_set_intfdata(interface, NULL);
+
+       /* Abort ongoing write */
+       if (atomic_read(&context->tx.busy)) {
+               usb_kill_urb(context->tx_urb);
+               complete_all(&context->tx.finished);
+       }
+
+       context->dev_present = 0;
+       usb_kill_urb(context->rx_urb);
+       if (context->display)
+               usb_deregister_dev(interface, &imon_class);
+
+       if (!context->ir_isopen && !context->dev_present) {
+               deregister_from_lirc(context);
+               mutex_unlock(&context->ctx_lock);
+               if (!context->display_isopen)
+                       free_imon_context(context);
+       } else
+               mutex_unlock(&context->ctx_lock);
+
+       mutex_unlock(&driver_lock);
+
+       printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n",
+              __func__, ifnum);
+}
+
+static int imon_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct imon_context *context = usb_get_intfdata(intf);
+
+       usb_kill_urb(context->rx_urb);
+
+       return 0;
+}
+
+static int imon_resume(struct usb_interface *intf)
+{
+       int rc = 0;
+       struct imon_context *context = usb_get_intfdata(intf);
+
+       usb_fill_int_urb(context->rx_urb, context->usbdev,
+               usb_rcvintpipe(context->usbdev,
+                       context->rx_endpoint->bEndpointAddress),
+               context->usb_rx_buf, sizeof(context->usb_rx_buf),
+               usb_rx_callback, context,
+               context->rx_endpoint->bInterval);
+
+       rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+       return rc;
+}
+
+static int __init imon_init(void)
+{
+       int rc;
+
+       printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n");
+
+       rc = usb_register(&imon_driver);
+       if (rc) {
+               err("%s: usb register failed(%d)", __func__, rc);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit imon_exit(void)
+{
+       usb_deregister(&imon_driver);
+       printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n");
+}
+
+module_init(imon_init);
+module_exit(imon_exit);
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c
new file mode 100644 (file)
index 0000000..09f3696
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ * 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 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 (module_refcount(THIS_MODULE)) {
+               spin_unlock(&dev_lock);
+               return -EBUSY;
+       }
+       spin_unlock(&dev_lock);
+       return 0;
+}
+
+
+static int lirc_close(struct inode *inode, struct file *file)
+{
+       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]);
+       return n;
+}
+
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int retval = 0;
+       unsigned long value = 0;
+       unsigned int ivalue;
+       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, (unsigned long *) arg);
+               break;
+
+       case LIRC_SET_SEND_MODE:
+       case LIRC_SET_REC_MODE:
+               retval = get_user(value, (unsigned long *) arg);
+               break;
+
+       case LIRC_SET_SEND_CARRIER:
+               retval = get_user(ivalue, (unsigned int *) arg);
+               if (retval)
+                       return retval;
+               ivalue /= 1000;
+               if (ivalue > IT87_CIR_FREQ_MAX ||
+                   ivalue < IT87_CIR_FREQ_MIN)
+                       return -EINVAL;
+
+               it87_freq = ivalue;
+
+               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,
+       .open           = lirc_open,
+       .release        = lirc_close,
+};
+
+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,
+};
+
+
+#ifdef 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);
+}
+#endif
+
+
+/* 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/18 */
+
+static const struct pnp_device_id pnp_dev_table[] = {
+       {"ITE8704", 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
new file mode 100644 (file)
index 0000000..cf021c8
--- /dev/null
@@ -0,0 +1,116 @@
+/* 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
new file mode 100644 (file)
index 0000000..9352f45
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * 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;
+       unsigned long long acc_pulse;
+       unsigned long long 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,
+                                       unsigned long long 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");
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c
new file mode 100644 (file)
index 0000000..a1ebd07
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * lirc_parallel.c
+ *
+ * lirc_parallel - device driver for infra-red signal receiving and
+ *                 transmitting unit built by the author
+ *
+ * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.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
+ *
+ */
+
+/*** Includes ***/
+
+#ifdef CONFIG_SMP
+#error "--- Sorry, this driver is not SMP safe. ---"
+#endif
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <linux/io.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <asm/div64.h>
+
+#include <linux/poll.h>
+#include <linux/parport.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include "lirc_parallel.h"
+
+#define LIRC_DRIVER_NAME "lirc_parallel"
+
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 7
+#endif
+#ifndef LIRC_PORT
+#define LIRC_PORT 0x378
+#endif
+#ifndef LIRC_TIMER
+#define LIRC_TIMER 65536
+#endif
+
+/*** Global Variables ***/
+
+static int debug;
+static int check_pselecd;
+
+unsigned int irq = LIRC_IRQ;
+unsigned int io = LIRC_PORT;
+#ifdef LIRC_TIMER
+unsigned int timer;
+unsigned int default_timer = LIRC_TIMER;
+#endif
+
+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
+
+static int rbuf[RBUF_SIZE];
+
+DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
+
+unsigned int rptr;
+unsigned int wptr;
+unsigned int lost_irqs;
+int is_open;
+
+struct parport *pport;
+struct pardevice *ppdevice;
+int is_claimed;
+
+unsigned int tx_mask = 1;
+
+/*** Internal Functions ***/
+
+static unsigned int in(int offset)
+{
+       switch (offset) {
+       case LIRC_LP_BASE:
+               return parport_read_data(pport);
+       case LIRC_LP_STATUS:
+               return parport_read_status(pport);
+       case LIRC_LP_CONTROL:
+               return parport_read_control(pport);
+       }
+       return 0; /* make compiler happy */
+}
+
+static void out(int offset, int value)
+{
+       switch (offset) {
+       case LIRC_LP_BASE:
+               parport_write_data(pport, value);
+               break;
+       case LIRC_LP_CONTROL:
+               parport_write_control(pport, value);
+               break;
+       case LIRC_LP_STATUS:
+               printk(KERN_INFO "%s: attempt to write to status register\n",
+                      LIRC_DRIVER_NAME);
+               break;
+       }
+}
+
+static unsigned int lirc_get_timer(void)
+{
+       return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
+}
+
+static unsigned int lirc_get_signal(void)
+{
+       return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
+}
+
+static void lirc_on(void)
+{
+       out(LIRC_PORT_DATA, tx_mask);
+}
+
+static void lirc_off(void)
+{
+       out(LIRC_PORT_DATA, 0);
+}
+
+static unsigned int init_lirc_timer(void)
+{
+       struct timeval tv, now;
+       unsigned int level, newlevel, timeelapsed, newtimer;
+       int count = 0;
+
+       do_gettimeofday(&tv);
+       tv.tv_sec++;                     /* wait max. 1 sec. */
+       level = lirc_get_timer();
+       do {
+               newlevel = lirc_get_timer();
+               if (level == 0 && newlevel != 0)
+                       count++;
+               level = newlevel;
+               do_gettimeofday(&now);
+       } while (count < 1000 && (now.tv_sec < tv.tv_sec
+                            || (now.tv_sec == tv.tv_sec
+                                && now.tv_usec < tv.tv_usec)));
+
+       timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
+                    + (now.tv_usec - tv.tv_usec));
+       if (count >= 1000 && timeelapsed > 0) {
+               if (default_timer == 0) {
+                       /* autodetect timer */
+                       newtimer = (1000000*count)/timeelapsed;
+                       printk(KERN_INFO "%s: %u Hz timer detected\n",
+                              LIRC_DRIVER_NAME, newtimer);
+                       return newtimer;
+               }  else {
+                       newtimer = (1000000*count)/timeelapsed;
+                       if (abs(newtimer - default_timer) > default_timer/10) {
+                               /* bad timer */
+                               printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
+                                      LIRC_DRIVER_NAME, newtimer);
+                               printk(KERN_NOTICE "%s: using default timer: "
+                                      "%u Hz\n",
+                                      LIRC_DRIVER_NAME, default_timer);
+                               return default_timer;
+                       } else {
+                               printk(KERN_INFO "%s: %u Hz timer detected\n",
+                                      LIRC_DRIVER_NAME, newtimer);
+                               return newtimer; /* use detected value */
+                       }
+               }
+       } else {
+               printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
+               return 0;
+       }
+}
+
+static int lirc_claim(void)
+{
+       if (parport_claim(ppdevice) != 0) {
+               printk(KERN_WARNING "%s: could not claim port\n",
+                      LIRC_DRIVER_NAME);
+               printk(KERN_WARNING "%s: waiting for port becoming available"
+                      "\n", LIRC_DRIVER_NAME);
+               if (parport_claim_or_block(ppdevice) < 0) {
+                       printk(KERN_NOTICE "%s: could not claim port, giving"
+                              " up\n", LIRC_DRIVER_NAME);
+                       return 0;
+               }
+       }
+       out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+       is_claimed = 1;
+       return 1;
+}
+
+/*** interrupt handler ***/
+
+static void rbuf_write(int signal)
+{
+       unsigned int nwptr;
+
+       nwptr = (wptr + 1) & (RBUF_SIZE - 1);
+       if (nwptr == rptr) {
+               /* no new signals will be accepted */
+               lost_irqs++;
+               printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
+               return;
+       }
+       rbuf[wptr] = signal;
+       wptr = nwptr;
+}
+
+static void irq_handler(void *blah)
+{
+       struct timeval tv;
+       static struct timeval lasttv;
+       static int init;
+       long signal;
+       int data;
+       unsigned int level, newlevel;
+       unsigned int timeout;
+
+       if (!module_refcount(THIS_MODULE))
+               return;
+
+       if (!is_claimed)
+               return;
+
+#if 0
+       /* disable interrupt */
+         disable_irq(irq);
+         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
+#endif
+       if (check_pselecd && (in(1) & LP_PSELECD))
+               return;
+
+#ifdef LIRC_TIMER
+       if (init) {
+               do_gettimeofday(&tv);
+
+               signal = tv.tv_sec - lasttv.tv_sec;
+               if (signal > 15)
+                       /* really long time */
+                       data = PULSE_MASK;
+               else
+                       data = (int) (signal*1000000 +
+                                        tv.tv_usec - lasttv.tv_usec +
+                                        LIRC_SFH506_DELAY);
+
+               rbuf_write(data); /* space */
+       } else {
+               if (timer == 0) {
+                       /*
+                        * wake up; we'll lose this signal, but it will be
+                        * garbage if the device is turned on anyway
+                        */
+                       timer = init_lirc_timer();
+                       /* enable_irq(irq); */
+                       return;
+               }
+               init = 1;
+       }
+
+       timeout = timer/10;     /* timeout after 1/10 sec. */
+       signal = 1;
+       level = lirc_get_timer();
+       do {
+               newlevel = lirc_get_timer();
+               if (level == 0 && newlevel != 0)
+                       signal++;
+               level = newlevel;
+
+               /* giving up */
+               if (signal > timeout
+                   || (check_pselecd && (in(1) & LP_PSELECD))) {
+                       signal = 0;
+                       printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
+                       break;
+               }
+       } while (lirc_get_signal());
+
+       if (signal != 0) {
+               /* ajust value to usecs */
+               unsigned long long helper;
+
+               helper = ((unsigned long long) signal)*1000000;
+               do_div(helper, timer);
+               signal = (long) helper;
+
+               if (signal > LIRC_SFH506_DELAY)
+                       data = signal - LIRC_SFH506_DELAY;
+               else
+                       data = 1;
+               rbuf_write(PULSE_BIT|data); /* pulse */
+       }
+       do_gettimeofday(&lasttv);
+#else
+       /* add your code here */
+#endif
+
+       wake_up_interruptible(&lirc_wait);
+
+       /* enable interrupt */
+       /*
+         enable_irq(irq);
+         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
+       */
+}
+
+/*** file operations ***/
+
+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
+{
+       return -ESPIPE;
+}
+
+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
+{
+       int result = 0;
+       int count = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (n % sizeof(int))
+               return -EINVAL;
+
+       add_wait_queue(&lirc_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (count < n) {
+               if (rptr != wptr) {
+                       if (copy_to_user(buf+count, (char *) &rbuf[rptr],
+                                        sizeof(int))) {
+                               result = -EFAULT;
+                               break;
+                       }
+                       rptr = (rptr + 1) & (RBUF_SIZE - 1);
+                       count += sizeof(int);
+               } else {
+                       if (filep->f_flags & O_NONBLOCK) {
+                               result = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               result = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+       }
+       remove_wait_queue(&lirc_wait, &wait);
+       set_current_state(TASK_RUNNING);
+       return count ? count : result;
+}
+
+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
+                         loff_t *ppos)
+{
+       int count;
+       unsigned int i;
+       unsigned int level, newlevel;
+       unsigned long flags;
+       int counttimer;
+       int *wbuf;
+
+       if (!is_claimed)
+               return -EBUSY;
+
+       count = n / sizeof(int);
+
+       if (n % sizeof(int) || count % 2 == 0)
+               return -EINVAL;
+
+       wbuf = memdup_user(buf, n);
+       if (IS_ERR(wbuf))
+               return PTR_ERR(wbuf);
+
+#ifdef LIRC_TIMER
+       if (timer == 0) {
+               /* try again if device is ready */
+               timer = init_lirc_timer();
+               if (timer == 0)
+                       return -EIO;
+       }
+
+       /* adjust values from usecs */
+       for (i = 0; i < count; i++) {
+               unsigned long long helper;
+
+               helper = ((unsigned long long) wbuf[i])*timer;
+               do_div(helper, 1000000);
+               wbuf[i] = (int) helper;
+       }
+
+       local_irq_save(flags);
+       i = 0;
+       while (i < count) {
+               level = lirc_get_timer();
+               counttimer = 0;
+               lirc_on();
+               do {
+                       newlevel = lirc_get_timer();
+                       if (level == 0 && newlevel != 0)
+                               counttimer++;
+                       level = newlevel;
+                       if (check_pselecd && (in(1) & LP_PSELECD)) {
+                               lirc_off();
+                               local_irq_restore(flags);
+                               return -EIO;
+                       }
+               } while (counttimer < wbuf[i]);
+               i++;
+
+               lirc_off();
+               if (i == count)
+                       break;
+               counttimer = 0;
+               do {
+                       newlevel = lirc_get_timer();
+                       if (level == 0 && newlevel != 0)
+                               counttimer++;
+                       level = newlevel;
+                       if (check_pselecd && (in(1) & LP_PSELECD)) {
+                               local_irq_restore(flags);
+                               return -EIO;
+                       }
+               } while (counttimer < wbuf[i]);
+               i++;
+       }
+       local_irq_restore(flags);
+#else
+       /* place code that handles write without external timer here */
+#endif
+       return n;
+}
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &lirc_wait, wait);
+       if (rptr != wptr)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int result;
+       unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK |
+                                LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+       unsigned long mode;
+       unsigned int ivalue;
+
+       switch (cmd) {
+       case LIRC_GET_FEATURES:
+               result = put_user(features, (unsigned long *) arg);
+               if (result)
+                       return result;
+               break;
+       case LIRC_GET_SEND_MODE:
+               result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+               if (result)
+                       return result;
+               break;
+       case LIRC_GET_REC_MODE:
+               result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg);
+               if (result)
+                       return result;
+               break;
+       case LIRC_SET_SEND_MODE:
+               result = get_user(mode, (unsigned long *) arg);
+               if (result)
+                       return result;
+               if (mode != LIRC_MODE_PULSE)
+                       return -EINVAL;
+               break;
+       case LIRC_SET_REC_MODE:
+               result = get_user(mode, (unsigned long *) arg);
+               if (result)
+                       return result;
+               if (mode != LIRC_MODE_MODE2)
+                       return -ENOSYS;
+               break;
+       case LIRC_SET_TRANSMITTER_MASK:
+               result = get_user(ivalue, (unsigned int *) arg);
+               if (result)
+                       return result;
+               if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue)
+                       return LIRC_PARALLEL_MAX_TRANSMITTERS;
+               tx_mask = ivalue;
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int lirc_open(struct inode *node, struct file *filep)
+{
+       if (module_refcount(THIS_MODULE) || !lirc_claim())
+               return -EBUSY;
+
+       parport_enable_irq(pport);
+
+       /* init read ptr */
+       rptr = 0;
+       wptr = 0;
+       lost_irqs = 0;
+
+       is_open = 1;
+       return 0;
+}
+
+static int lirc_close(struct inode *node, struct file *filep)
+{
+       if (is_claimed) {
+               is_claimed = 0;
+               parport_release(ppdevice);
+       }
+       is_open = 0;
+       return 0;
+}
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = lirc_lseek,
+       .read           = lirc_read,
+       .write          = lirc_write,
+       .poll           = lirc_poll,
+       .unlocked_ioctl = lirc_ioctl,
+       .open           = lirc_open,
+       .release        = lirc_close
+};
+
+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 pf(void *handle);
+static void kf(void *handle);
+
+static struct timer_list poll_timer;
+static void poll_state(unsigned long ignored);
+
+static void poll_state(unsigned long ignored)
+{
+       printk(KERN_NOTICE "%s: time\n",
+              LIRC_DRIVER_NAME);
+       del_timer(&poll_timer);
+       if (is_claimed)
+               return;
+       kf(NULL);
+       if (!is_claimed) {
+               printk(KERN_NOTICE "%s: could not claim port, giving up\n",
+                      LIRC_DRIVER_NAME);
+               init_timer(&poll_timer);
+               poll_timer.expires = jiffies + HZ;
+               poll_timer.data = (unsigned long)current;
+               poll_timer.function = poll_state;
+               add_timer(&poll_timer);
+       }
+}
+
+static int pf(void *handle)
+{
+       parport_disable_irq(pport);
+       is_claimed = 0;
+       return 0;
+}
+
+static void kf(void *handle)
+{
+       if (!is_open)
+               return;
+       if (!lirc_claim())
+               return;
+       parport_enable_irq(pport);
+       lirc_off();
+       /* this is a bit annoying when you actually print...*/
+       /*
+       printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
+       */
+}
+
+/*** module initialization and cleanup ***/
+
+static int __init lirc_parallel_init(void)
+{
+       pport = parport_find_base(io);
+       if (pport == NULL) {
+               printk(KERN_NOTICE "%s: no port at %x found\n",
+                      LIRC_DRIVER_NAME, io);
+               return -ENXIO;
+       }
+       ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
+                                          pf, kf, irq_handler, 0, NULL);
+       parport_put_port(pport);
+       if (ppdevice == NULL) {
+               printk(KERN_NOTICE "%s: parport_register_device() failed\n",
+                      LIRC_DRIVER_NAME);
+               return -ENXIO;
+       }
+       if (parport_claim(ppdevice) != 0)
+               goto skip_init;
+       is_claimed = 1;
+       out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+
+#ifdef LIRC_TIMER
+       if (debug)
+               out(LIRC_PORT_DATA, tx_mask);
+
+       timer = init_lirc_timer();
+
+#if 0  /* continue even if device is offline */
+       if (timer == 0) {
+               is_claimed = 0;
+               parport_release(pport);
+               parport_unregister_device(ppdevice);
+               return -EIO;
+       }
+
+#endif
+       if (debug)
+               out(LIRC_PORT_DATA, 0);
+#endif
+
+       is_claimed = 0;
+       parport_release(ppdevice);
+ skip_init:
+       driver.minor = lirc_register_driver(&driver);
+       if (driver.minor < 0) {
+               printk(KERN_NOTICE "%s: register_chrdev() failed\n",
+                      LIRC_DRIVER_NAME);
+               parport_unregister_device(ppdevice);
+               return -EIO;
+       }
+       printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
+              LIRC_DRIVER_NAME, io, irq);
+       return 0;
+}
+
+static void __exit lirc_parallel_exit(void)
+{
+       parport_unregister_device(ppdevice);
+       lirc_unregister_driver(driver.minor);
+}
+
+module_init(lirc_parallel_init);
+module_exit(lirc_parallel_exit);
+
+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
+MODULE_AUTHOR("Christoph Bartelmus");
+MODULE_LICENSE("GPL");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
+
+module_param(tx_mask, int, S_IRUGO);
+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Check for printer (default: 0)");
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h
new file mode 100644 (file)
index 0000000..4bed6af
--- /dev/null
@@ -0,0 +1,26 @@
+/* lirc_parallel.h */
+
+#ifndef _LIRC_PARALLEL_H
+#define _LIRC_PARALLEL_H
+
+#include <linux/lp.h>
+
+#define LIRC_PORT_LEN 3
+
+#define LIRC_LP_BASE    0
+#define LIRC_LP_STATUS  1
+#define LIRC_LP_CONTROL 2
+
+#define LIRC_PORT_DATA           LIRC_LP_BASE    /* base */
+#define LIRC_PORT_TIMER        LIRC_LP_STATUS    /* status port */
+#define LIRC_PORT_TIMER_BIT          LP_PBUSY    /* busy signal */
+#define LIRC_PORT_SIGNAL       LIRC_LP_STATUS    /* status port */
+#define LIRC_PORT_SIGNAL_BIT          LP_PACK    /* ack signal */
+#define LIRC_PORT_IRQ         LIRC_LP_CONTROL    /* control port */
+
+#define LIRC_SFH506_DELAY 0             /* delay t_phl in usecs */
+
+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8
+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1)
+
+#endif
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c
new file mode 100644 (file)
index 0000000..73166c3
--- /dev/null
@@ -0,0 +1,933 @@
+/*
+ * lirc_sasem.c - USB remote support for LIRC
+ * Version 0.5
+ *
+ * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de>
+ *                      Tim Davies <tim@opensystems.net.au>
+ *
+ * This driver was derived from:
+ *   Venky Raju <dev@venky.ws>
+ *      "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
+ *   Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004
+ *      "lirc_atiusb - USB remote support for LIRC"
+ *   Culver Consulting Services <henry@culcon.com>'s 2003
+ *      "Sasem OnAir VFD/IR USB driver"
+ *
+ *
+ * NOTE - The LCDproc iMon driver should work with this module.  More info at
+ *     http://www.frogstorm.info/sasem
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR     "Oliver Stabel <oliver.stabel@gmx.de>, " \
+                       "Tim Davies <tim@opensystems.net.au>"
+#define MOD_DESC       "USB Driver for Sasem Remote Controller V1.1"
+#define MOD_NAME       "lirc_sasem"
+#define MOD_VERSION    "0.5"
+
+#define VFD_MINOR_BASE 144     /* Same as LCD */
+#define DEVICE_NAME    "lcd%d"
+
+#define BUF_CHUNK_SIZE 8
+#define BUF_SIZE       128
+
+#define IOCTL_LCD_CONTRAST 1
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int sasem_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id);
+static void sasem_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* VFD file_operations function prototypes */
+static int vfd_open(struct inode *inode, struct file *file);
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
+static int vfd_close(struct inode *inode, struct file *file);
+static ssize_t vfd_write(struct file *file, const char *buf,
+                               size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init sasem_init(void);
+static void __exit sasem_exit(void);
+
+/*** G L O B A L S ***/
+#define SASEM_DATA_BUF_SZ      32
+
+struct sasem_context {
+
+       struct usb_device *dev;
+       int vfd_isopen;                 /* VFD port has been opened       */
+       unsigned int vfd_contrast;      /* VFD contrast            */
+       int ir_isopen;                  /* IR port has been opened      */
+       int dev_present;                /* USB device presence      */
+       struct mutex ctx_lock;          /* to lock this object      */
+       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
+
+       struct lirc_driver *driver;
+       struct usb_endpoint_descriptor *rx_endpoint;
+       struct usb_endpoint_descriptor *tx_endpoint;
+       struct urb *rx_urb;
+       struct urb *tx_urb;
+       unsigned char usb_rx_buf[8];
+       unsigned char usb_tx_buf[8];
+
+       struct tx_t {
+               unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */
+               struct completion finished;  /* wait for write to finish  */
+               atomic_t busy;               /* write in progress        */
+               int status;                  /* status of tx completion   */
+       } tx;
+
+       /* for dealing with repeat codes (wish there was a toggle bit!) */
+       struct timeval presstime;
+       char lastcode[8];
+       int codesaved;
+};
+
+/* VFD file operations */
+static const struct file_operations vfd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &vfd_open,
+       .write          = &vfd_write,
+       .unlocked_ioctl = &vfd_ioctl,
+       .release        = &vfd_close,
+};
+
+/* USB Device ID for Sasem USB Control Board */
+static struct usb_device_id sasem_usb_id_table[] = {
+       /* Sasem USB Control Board */
+       { USB_DEVICE(0x11ba, 0x0101) },
+       /* Terminating entry */
+       {}
+};
+
+/* USB Device data */
+static struct usb_driver sasem_driver = {
+       .name           = MOD_NAME,
+       .probe          = sasem_probe,
+       .disconnect     = sasem_disconnect,
+       .id_table       = sasem_usb_id_table,
+};
+
+static struct usb_class_driver sasem_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &vfd_fops,
+       .minor_base     = VFD_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect() */
+static DEFINE_MUTEX(disconnect_lock);
+
+static int debug;
+
+
+/*** M O D U L E   C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
+
+static void delete_context(struct sasem_context *context)
+{
+       usb_free_urb(context->tx_urb);  /* VFD */
+       usb_free_urb(context->rx_urb);  /* IR */
+       lirc_buffer_free(context->driver->rbuf);
+       kfree(context->driver->rbuf);
+       kfree(context->driver);
+       kfree(context);
+
+       if (debug)
+               printk(KERN_INFO "%s: context deleted\n", __func__);
+}
+
+static void deregister_from_lirc(struct sasem_context *context)
+{
+       int retval;
+       int minor = context->driver->minor;
+
+       retval = lirc_unregister_driver(minor);
+       if (retval)
+               err("%s: unable to deregister from lirc (%d)",
+                       __func__, retval);
+       else
+               printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
+                      minor);
+
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is opened by the application.
+ */
+static int vfd_open(struct inode *inode, struct file *file)
+{
+       struct usb_interface *interface;
+       struct sasem_context *context = NULL;
+       int subminor;
+       int retval = 0;
+
+       /* prevent races with disconnect */
+       mutex_lock(&disconnect_lock);
+
+       subminor = iminor(inode);
+       interface = usb_find_interface(&sasem_driver, subminor);
+       if (!interface) {
+               err("%s: could not find interface for minor %d",
+                   __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+       context = usb_get_intfdata(interface);
+
+       if (!context) {
+               err("%s: no context found for minor %d",
+                                       __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (context->vfd_isopen) {
+               err("%s: VFD port is already open", __func__);
+               retval = -EBUSY;
+       } else {
+               context->vfd_isopen = 1;
+               file->private_data = context;
+               printk(KERN_INFO "VFD port opened\n");
+       }
+
+       mutex_unlock(&context->ctx_lock);
+
+exit:
+       mutex_unlock(&disconnect_lock);
+       return retval;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+       struct sasem_context *context = NULL;
+
+       context = (struct sasem_context *) file->private_data;
+
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       switch (cmd) {
+       case IOCTL_LCD_CONTRAST:
+               if (arg > 1000)
+                       arg = 1000;
+               context->vfd_contrast = (unsigned int)arg;
+               break;
+       default:
+               printk(KERN_INFO "Unknown IOCTL command\n");
+               mutex_unlock(&context->ctx_lock);
+               return -ENOIOCTLCMD;  /* not supported */
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return 0;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static int vfd_close(struct inode *inode, struct file *file)
+{
+       struct sasem_context *context = NULL;
+       int retval = 0;
+
+       context = (struct sasem_context *) file->private_data;
+
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->vfd_isopen) {
+               err("%s: VFD is not open", __func__);
+               retval = -EIO;
+       } else {
+               context->vfd_isopen = 0;
+               printk(KERN_INFO "VFD port closed\n");
+               if (!context->dev_present && !context->ir_isopen) {
+
+                       /* Device disconnected before close and IR port is
+                        * not open. If IR port is open, context will be
+                        * deleted by ir_close. */
+                       mutex_unlock(&context->ctx_lock);
+                       delete_context(context);
+                       return retval;
+               }
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return retval;
+}
+
+/**
+ * Sends a packet to the VFD.
+ */
+static int send_packet(struct sasem_context *context)
+{
+       unsigned int pipe;
+       int interval = 0;
+       int retval = 0;
+
+       pipe = usb_sndintpipe(context->dev,
+                       context->tx_endpoint->bEndpointAddress);
+       interval = context->tx_endpoint->bInterval;
+
+       usb_fill_int_urb(context->tx_urb, context->dev, pipe,
+               context->usb_tx_buf, sizeof(context->usb_tx_buf),
+               usb_tx_callback, context, interval);
+
+       context->tx_urb->actual_length = 0;
+
+       init_completion(&context->tx.finished);
+       atomic_set(&(context->tx.busy), 1);
+
+       retval =  usb_submit_urb(context->tx_urb, GFP_KERNEL);
+       if (retval) {
+               atomic_set(&(context->tx.busy), 0);
+               err("%s: error submitting urb (%d)", __func__, retval);
+       } else {
+               /* Wait for transmission to complete (or abort) */
+               mutex_unlock(&context->ctx_lock);
+               wait_for_completion(&context->tx.finished);
+               mutex_lock(&context->ctx_lock);
+
+               retval = context->tx.status;
+               if (retval)
+                       err("%s: packet tx failed (%d)", __func__, retval);
+       }
+
+       return retval;
+}
+
+/**
+ * Writes data to the VFD.  The Sasem VFD is 2x16 characters
+ * and requires data in 9 consecutive USB interrupt packets,
+ * each packet carrying 8 bytes.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                               size_t n_bytes, loff_t *pos)
+{
+       int i;
+       int retval = 0;
+       struct sasem_context *context;
+       int *data_buf;
+
+       context = (struct sasem_context *) file->private_data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->dev_present) {
+               err("%s: no Sasem device present", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
+               err("%s: invalid payload size", __func__);
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       data_buf = memdup_user(buf, n_bytes);
+       if (PTR_ERR(data_buf))
+               return PTR_ERR(data_buf);
+
+       memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+       /* Pad with spaces */
+       for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
+               context->tx.data_buf[i] = ' ';
+
+       /* Nine 8 byte packets to be sent */
+       /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
+        *       will clear the VFD */
+       for (i = 0; i < 9; i++) {
+               switch (i) {
+               case 0:
+                       memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
+                       context->usb_tx_buf[1] = (context->vfd_contrast) ?
+                               (0x2B - (context->vfd_contrast - 1) / 250)
+                               : 0x2B;
+                       break;
+               case 1:
+                       memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+                       break;
+               case 2:
+                       memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
+                       break;
+               case 3:
+                       memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
+                       break;
+               case 4:
+                       memcpy(context->usb_tx_buf,
+                              context->tx.data_buf + 8, 8);
+                       break;
+               case 5:
+                       memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+                       break;
+               case 6:
+                       memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
+                       break;
+               case 7:
+                       memcpy(context->usb_tx_buf,
+                              context->tx.data_buf + 16, 8);
+                       break;
+               case 8:
+                       memcpy(context->usb_tx_buf,
+                              context->tx.data_buf + 24, 8);
+                       break;
+               }
+               retval = send_packet(context);
+               if (retval) {
+
+                       err("%s: send packet failed for packet #%d",
+                                       __func__, i);
+                       goto exit;
+               }
+       }
+exit:
+
+       mutex_unlock(&context->ctx_lock);
+
+       return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+       struct sasem_context *context;
+
+       if (!urb)
+               return;
+       context = (struct sasem_context *) urb->context;
+       if (!context)
+               return;
+
+       context->tx.status = urb->status;
+
+       /* notify waiters that write has finished */
+       atomic_set(&context->tx.busy, 0);
+       complete(&context->tx.finished);
+
+       return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+       int retval = 0;
+       struct sasem_context *context;
+
+       /* prevent races with disconnect */
+       mutex_lock(&disconnect_lock);
+
+       context = (struct sasem_context *) data;
+
+       mutex_lock(&context->ctx_lock);
+
+       if (context->ir_isopen) {
+               err("%s: IR port is already open", __func__);
+               retval = -EBUSY;
+               goto exit;
+       }
+
+       usb_fill_int_urb(context->rx_urb, context->dev,
+               usb_rcvintpipe(context->dev,
+                               context->rx_endpoint->bEndpointAddress),
+               context->usb_rx_buf, sizeof(context->usb_rx_buf),
+               usb_rx_callback, context, context->rx_endpoint->bInterval);
+
+       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+       if (retval)
+               err("%s: usb_submit_urb failed for ir_open (%d)",
+                   __func__, retval);
+       else {
+               context->ir_isopen = 1;
+               printk(KERN_INFO "IR port opened\n");
+       }
+
+exit:
+       mutex_unlock(&context->ctx_lock);
+
+       mutex_unlock(&disconnect_lock);
+       return 0;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+       struct sasem_context *context;
+
+       context = (struct sasem_context *)data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       usb_kill_urb(context->rx_urb);
+       context->ir_isopen = 0;
+       printk(KERN_INFO "IR port closed\n");
+
+       if (!context->dev_present) {
+
+               /*
+                * Device disconnected while IR port was
+                * still open. Driver was not deregistered
+                * at disconnect time, so do it now.
+                */
+               deregister_from_lirc(context);
+
+               if (!context->vfd_isopen) {
+
+                       mutex_unlock(&context->ctx_lock);
+                       delete_context(context);
+                       return;
+               }
+               /* If VFD port is open, context will be deleted by vfd_close */
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void incoming_packet(struct sasem_context *context,
+                                  struct urb *urb)
+{
+       int len = urb->actual_length;
+       unsigned char *buf = urb->transfer_buffer;
+       long ms;
+       struct timeval tv;
+
+       if (len != 8) {
+               printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
+                    __func__, len);
+               return;
+       }
+
+#ifdef DEBUG
+       int i;
+       for (i = 0; i < 8; ++i)
+               printk(KERN_INFO "%02x ", buf[i]);
+       printk(KERN_INFO "\n");
+#endif
+
+       /*
+        * Lirc could deal with the repeat code, but we really need to block it
+        * if it arrives too late.  Otherwise we could repeat the wrong code.
+        */
+
+       /* get the time since the last button press */
+       do_gettimeofday(&tv);
+       ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
+            (tv.tv_usec - context->presstime.tv_usec) / 1000;
+
+       if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
+               /*
+                * the repeat code is being sent, so we copy
+                * the old code to LIRC
+                */
+
+               /*
+                * NOTE: Only if the last code was less than 250ms ago
+                * - no one should be able to push another (undetected) button
+                *   in that time and then get a false repeat of the previous
+                *   press but it is long enough for a genuine repeat
+                */
+               if ((ms < 250) && (context->codesaved != 0)) {
+                       memcpy(buf, &context->lastcode, 8);
+                       context->presstime.tv_sec = tv.tv_sec;
+                       context->presstime.tv_usec = tv.tv_usec;
+               }
+       } else {
+               /* save the current valid code for repeats */
+               memcpy(&context->lastcode, buf, 8);
+               /*
+                * set flag to signal a valid code was save;
+                * just for safety reasons
+                */
+               context->codesaved = 1;
+               context->presstime.tv_sec = tv.tv_sec;
+               context->presstime.tv_usec = tv.tv_usec;
+       }
+
+       lirc_buffer_write(context->driver->rbuf, buf);
+       wake_up(&context->driver->rbuf->wait_poll);
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+       struct sasem_context *context;
+
+       if (!urb)
+               return;
+       context = (struct sasem_context *) urb->context;
+       if (!context)
+               return;
+
+       switch (urb->status) {
+
+       case -ENOENT:           /* usbcore unlink successful! */
+               return;
+
+       case 0:
+               if (context->ir_isopen)
+                       incoming_packet(context, urb);
+               break;
+
+       default:
+               printk(KERN_WARNING "%s: status (%d): ignored",
+                        __func__, urb->status);
+               break;
+       }
+
+       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+       return;
+}
+
+
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int sasem_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id)
+{
+       struct usb_device *dev = NULL;
+       struct usb_host_interface *iface_desc = NULL;
+       struct usb_endpoint_descriptor *rx_endpoint = NULL;
+       struct usb_endpoint_descriptor *tx_endpoint = NULL;
+       struct urb *rx_urb = NULL;
+       struct urb *tx_urb = NULL;
+       struct lirc_driver *driver = NULL;
+       struct lirc_buffer *rbuf = NULL;
+       int lirc_minor = 0;
+       int num_endpoints;
+       int retval = 0;
+       int vfd_ep_found;
+       int ir_ep_found;
+       int alloc_status;
+       struct sasem_context *context = NULL;
+       int i;
+
+       printk(KERN_INFO "%s: found Sasem device\n", __func__);
+
+
+       dev = usb_get_dev(interface_to_usbdev(interface));
+       iface_desc = interface->cur_altsetting;
+       num_endpoints = iface_desc->desc.bNumEndpoints;
+
+       /*
+        * Scan the endpoint list and set:
+        *      first input endpoint = IR endpoint
+        *      first output endpoint = VFD endpoint
+        */
+
+       ir_ep_found = 0;
+       vfd_ep_found = 0;
+
+       for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
+
+               struct usb_endpoint_descriptor *ep;
+               int ep_dir;
+               int ep_type;
+               ep = &iface_desc->endpoint [i].desc;
+               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (!ir_ep_found &&
+                       ep_dir == USB_DIR_IN &&
+                       ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       rx_endpoint = ep;
+                       ir_ep_found = 1;
+                       if (debug)
+                               printk(KERN_INFO "%s: found IR endpoint\n",
+                                      __func__);
+
+               } else if (!vfd_ep_found &&
+                       ep_dir == USB_DIR_OUT &&
+                       ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       tx_endpoint = ep;
+                       vfd_ep_found = 1;
+                       if (debug)
+                               printk(KERN_INFO "%s: found VFD endpoint\n",
+                                      __func__);
+               }
+       }
+
+       /* Input endpoint is mandatory */
+       if (!ir_ep_found) {
+
+               err("%s: no valid input (IR) endpoint found.", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (!vfd_ep_found)
+               printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
+                      __func__);
+
+
+       /* Allocate memory */
+       alloc_status = 0;
+
+       context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
+       if (!context) {
+               err("%s: kzalloc failed for context", __func__);
+               alloc_status = 1;
+               goto alloc_status_switch;
+       }
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver) {
+               err("%s: kzalloc failed for lirc_driver", __func__);
+               alloc_status = 2;
+               goto alloc_status_switch;
+       }
+       rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!rbuf) {
+               err("%s: kmalloc failed for lirc_buffer", __func__);
+               alloc_status = 3;
+               goto alloc_status_switch;
+       }
+       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+               err("%s: lirc_buffer_init failed", __func__);
+               alloc_status = 4;
+               goto alloc_status_switch;
+       }
+       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rx_urb) {
+               err("%s: usb_alloc_urb failed for IR urb", __func__);
+               alloc_status = 5;
+               goto alloc_status_switch;
+       }
+       if (vfd_ep_found) {
+               tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!tx_urb) {
+                       err("%s: usb_alloc_urb failed for VFD urb",
+                           __func__);
+                       alloc_status = 6;
+                       goto alloc_status_switch;
+               }
+       }
+
+       mutex_init(&context->ctx_lock);
+
+       strcpy(driver->name, MOD_NAME);
+       driver->minor = -1;
+       driver->code_length = 64;
+       driver->sample_rate = 0;
+       driver->features = LIRC_CAN_REC_LIRCCODE;
+       driver->data = context;
+       driver->rbuf = rbuf;
+       driver->set_use_inc = ir_open;
+       driver->set_use_dec = ir_close;
+       driver->dev   = &interface->dev;
+       driver->owner = THIS_MODULE;
+
+       mutex_lock(&context->ctx_lock);
+
+       lirc_minor = lirc_register_driver(driver);
+       if (lirc_minor < 0) {
+               err("%s: lirc_register_driver failed", __func__);
+               alloc_status = 7;
+               mutex_unlock(&context->ctx_lock);
+       } else
+               printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n",
+                       __func__, lirc_minor);
+
+alloc_status_switch:
+
+       switch (alloc_status) {
+
+       case 7:
+               if (vfd_ep_found)
+                       usb_free_urb(tx_urb);
+       case 6:
+               usb_free_urb(rx_urb);
+       case 5:
+               lirc_buffer_free(rbuf);
+       case 4:
+               kfree(rbuf);
+       case 3:
+               kfree(driver);
+       case 2:
+               kfree(context);
+               context = NULL;
+       case 1:
+               retval = -ENOMEM;
+               goto exit;
+       }
+
+       /* Needed while unregistering! */
+       driver->minor = lirc_minor;
+
+       context->dev = dev;
+       context->dev_present = 1;
+       context->rx_endpoint = rx_endpoint;
+       context->rx_urb = rx_urb;
+       if (vfd_ep_found) {
+               context->tx_endpoint = tx_endpoint;
+               context->tx_urb = tx_urb;
+               context->vfd_contrast = 1000;   /* range 0 - 1000 */
+       }
+       context->driver = driver;
+
+       usb_set_intfdata(interface, context);
+
+       if (vfd_ep_found) {
+
+               if (debug)
+                       printk(KERN_INFO "Registering VFD with sysfs\n");
+               if (usb_register_dev(interface, &sasem_class))
+                       /* Not a fatal error, so ignore */
+                       printk(KERN_INFO "%s: could not get a minor number "
+                              "for VFD\n", __func__);
+       }
+
+       printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n",
+                       __func__, dev->bus->busnum, dev->devnum);
+
+       mutex_unlock(&context->ctx_lock);
+exit:
+       return retval;
+}
+
+/**
+ * Callback function for USB core API: disonnect
+ */
+static void sasem_disconnect(struct usb_interface *interface)
+{
+       struct sasem_context *context;
+
+       /* prevent races with ir_open()/vfd_open() */
+       mutex_lock(&disconnect_lock);
+
+       context = usb_get_intfdata(interface);
+       mutex_lock(&context->ctx_lock);
+
+       printk(KERN_INFO "%s: Sasem device disconnected\n", __func__);
+
+       usb_set_intfdata(interface, NULL);
+       context->dev_present = 0;
+
+       /* Stop reception */
+       usb_kill_urb(context->rx_urb);
+
+       /* Abort ongoing write */
+       if (atomic_read(&context->tx.busy)) {
+
+               usb_kill_urb(context->tx_urb);
+               wait_for_completion(&context->tx.finished);
+       }
+
+       /* De-register from lirc_dev if IR port is not open */
+       if (!context->ir_isopen)
+               deregister_from_lirc(context);
+
+       usb_deregister_dev(interface, &sasem_class);
+
+       mutex_unlock(&context->ctx_lock);
+
+       if (!context->ir_isopen && !context->vfd_isopen)
+               delete_context(context);
+
+       mutex_unlock(&disconnect_lock);
+}
+
+static int __init sasem_init(void)
+{
+       int rc;
+
+       printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n");
+       printk(KERN_INFO MOD_AUTHOR "\n");
+
+       rc = usb_register(&sasem_driver);
+       if (rc < 0) {
+               err("%s: usb register failed (%d)", __func__, rc);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit sasem_exit(void)
+{
+       usb_deregister(&sasem_driver);
+       printk(KERN_INFO "module removed. Goodbye!\n");
+}
+
+
+module_init(sasem_init);
+module_exit(sasem_exit);
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
new file mode 100644 (file)
index 0000000..9456f8e
--- /dev/null
@@ -0,0 +1,1313 @@
+/*
+ * lirc_serial.c
+ *
+ * lirc_serial - Device driver that records pulse- and pause-lengths
+ *            (space-lengths) between DDCD event on a serial port.
+ *
+ * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
+ * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
+ * Copyright (C) 1998 Ben Pfaff <blp@gnu.org>
+ * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
+ * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support)
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Steve's changes to improve transmission fidelity:
+ *   - for systems with the rdtsc instruction and the clock counter, a
+ *     send_pule that times the pulses directly using the counter.
+ *     This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is
+ *     not needed. Measurement shows very stable waveform, even where
+ *     PCI activity slows the access to the UART, which trips up other
+ *     versions.
+ *   - For other system, non-integer-microsecond pulse/space lengths,
+ *     done using fixed point binary. So, much more accurate carrier
+ *     frequency.
+ *   - fine tuned transmitter latency, taking advantage of fractional
+ *     microseconds in previous change
+ *   - Fixed bug in the way transmitter latency was accounted for by
+ *     tuning the pulse lengths down - the send_pulse routine ignored
+ *     this overhead as it timed the overall pulse length - so the
+ *     pulse frequency was right but overall pulse length was too
+ *     long. Fixed by accounting for latency on each pulse/space
+ *     iteration.
+ *
+ * Steve Davies <steve@daviesfam.org>  July 2001
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.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 <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+#include <asm/hardware.h>
+#endif
+/* From Intel IXP42X Developer's Manual (#252480-005): */
+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */
+#define UART_IE_IXP42X_UUE   0x40 /* IXP42X UART Unit enable */
+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define LIRC_DRIVER_NAME "lirc_serial"
+
+struct lirc_serial {
+       int signal_pin;
+       int signal_pin_change;
+       u8 on;
+       u8 off;
+       long (*send_pulse)(unsigned long length);
+       void (*send_space)(long length);
+       int features;
+       spinlock_t lock;
+};
+
+#define LIRC_HOMEBREW          0
+#define LIRC_IRDEO             1
+#define LIRC_IRDEO_REMOTE      2
+#define LIRC_ANIMAX            3
+#define LIRC_IGOR              4
+#define LIRC_NSLU2             5
+
+/*** module parameters ***/
+static int type;
+static int io;
+static int irq;
+static int iommap;
+static int ioshift;
+static int softcarrier = 1;
+static int share_irq;
+static int debug;
+static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */
+static int txsense;    /* 0 = active high, 1 = active low */
+
+#define dprintk(fmt, args...)                                  \
+       do {                                                    \
+               if (debug)                                      \
+                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+                              fmt, ## args);                   \
+       } while (0)
+
+/* forward declarations */
+static long send_pulse_irdeo(unsigned long length);
+static long send_pulse_homebrew(unsigned long length);
+static void send_space_irdeo(long length);
+static void send_space_homebrew(long length);
+
+static struct lirc_serial hardware[] = {
+       [LIRC_HOMEBREW] = {
+               .signal_pin        = UART_MSR_DCD,
+               .signal_pin_change = UART_MSR_DDCD,
+               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+               .off = (UART_MCR_RTS | UART_MCR_OUT2),
+               .send_pulse = send_pulse_homebrew,
+               .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SET_SEND_CARRIER |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+               .features    = LIRC_CAN_REC_MODE2
+#endif
+       },
+
+       [LIRC_IRDEO] = {
+               .signal_pin        = UART_MSR_DSR,
+               .signal_pin_change = UART_MSR_DDSR,
+               .on  = UART_MCR_OUT2,
+               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .send_pulse  = send_pulse_irdeo,
+               .send_space  = send_space_irdeo,
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+       },
+
+       [LIRC_IRDEO_REMOTE] = {
+               .signal_pin        = UART_MSR_DSR,
+               .signal_pin_change = UART_MSR_DDSR,
+               .on  = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .send_pulse  = send_pulse_irdeo,
+               .send_space  = send_space_irdeo,
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+       },
+
+       [LIRC_ANIMAX] = {
+               .signal_pin        = UART_MSR_DCD,
+               .signal_pin_change = UART_MSR_DDCD,
+               .on  = 0,
+               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .send_pulse = NULL,
+               .send_space = NULL,
+               .features   = LIRC_CAN_REC_MODE2
+       },
+
+       [LIRC_IGOR] = {
+               .signal_pin        = UART_MSR_DSR,
+               .signal_pin_change = UART_MSR_DDSR,
+               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+               .off = (UART_MCR_RTS | UART_MCR_OUT2),
+               .send_pulse = send_pulse_homebrew,
+               .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SET_SEND_CARRIER |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+               .features    = LIRC_CAN_REC_MODE2
+#endif
+       },
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       /*
+        * Modified Linksys Network Storage Link USB 2.0 (NSLU2):
+        * We receive on CTS of the 2nd serial port (R142,LHS), we
+        * transmit with a IR diode between GPIO[1] (green status LED),
+        * and ground (Matthias Goebl <matthias.goebl@goebl.net>).
+        * See also http://www.nslu2-linux.org for this device
+        */
+       [LIRC_NSLU2] = {
+               .signal_pin        = UART_MSR_CTS,
+               .signal_pin_change = UART_MSR_DCTS,
+               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+               .off = (UART_MCR_RTS | UART_MCR_OUT2),
+               .send_pulse = send_pulse_homebrew,
+               .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SET_SEND_CARRIER |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+               .features    = LIRC_CAN_REC_MODE2
+#endif
+       },
+#endif
+
+};
+
+#define RS_ISR_PASS_LIMIT 256
+
+/*
+ * A long pulse code from a remote might take up to 300 bytes.  The
+ * daemon should read the bytes as soon as they are generated, so take
+ * the number of keys you think you can push before the daemon runs
+ * and multiply by 300.  The driver will warn you if you overrun this
+ * buffer.  If you have a slow computer or non-busmastering IDE disks,
+ * maybe you will need to increase this.
+ */
+
+/* This MUST be a power of two!  It has to be larger than 1 as well. */
+
+#define RBUF_LEN 256
+
+static struct timeval lasttv = {0, 0};
+
+static struct lirc_buffer rbuf;
+
+static unsigned int freq = 38000;
+static unsigned int duty_cycle = 50;
+
+/* Initialized in init_timing_params() */
+static unsigned long period;
+static unsigned long pulse_width;
+static unsigned long space_width;
+
+#if defined(__i386__)
+/*
+ * From:
+ * Linux I/O port programming mini-HOWTO
+ * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>
+ * v, 28 December 1997
+ *
+ * [...]
+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range
+ * takes almost exactly 1 microsecond, so if you're, for example, using
+ * the parallel port directly, just do additional inb()s from that port
+ * to delay.
+ * [...]
+ */
+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from
+ * comment above plus trimming to match actual measured frequency.
+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us
+ * is spent in the uart access.  Still - for reference test machine was a
+ * 1.13GHz Athlon system - Steve
+ */
+
+/*
+ * changed from 400 to 450 as this works better on slower machines;
+ * faster machines will use the rdtsc code anyway
+ */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450
+
+#else
+
+/* does anybody have information on other platforms ? */
+/* 256 = 1<<8 */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256
+
+#endif  /* __i386__ */
+/*
+ * FIXME: should we be using hrtimers instead of this
+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense?
+ */
+
+/* fetch serial input packet (1 byte) from register offset */
+static u8 sinp(int offset)
+{
+       if (iommap != 0)
+               /* the register is memory-mapped */
+               offset <<= ioshift;
+
+       return inb(io + offset);
+}
+
+/* write serial output packet (1 byte) of value to register offset */
+static void soutp(int offset, u8 value)
+{
+       if (iommap != 0)
+               /* the register is memory-mapped */
+               offset <<= ioshift;
+
+       outb(value, io + offset);
+}
+
+static void on(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       /*
+        * On NSLU2, we put the transmit diode between the output of the green
+        * status LED and ground
+        */
+       if (type == LIRC_NSLU2) {
+               gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW);
+               return;
+       }
+#endif
+       if (txsense)
+               soutp(UART_MCR, hardware[type].off);
+       else
+               soutp(UART_MCR, hardware[type].on);
+}
+
+static void off(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       if (type == LIRC_NSLU2) {
+               gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH);
+               return;
+       }
+#endif
+       if (txsense)
+               soutp(UART_MCR, hardware[type].on);
+       else
+               soutp(UART_MCR, hardware[type].off);
+}
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+       while (usecs > MAX_UDELAY_US) {
+               udelay(MAX_UDELAY_US);
+               usecs -= MAX_UDELAY_US;
+       }
+       udelay(usecs);
+}
+
+#ifdef USE_RDTSC
+/*
+ * This is an overflow/precision juggle, complicated in that we can't
+ * do long long divide in the kernel
+ */
+
+/*
+ * When we use the rdtsc instruction to measure clocks, we keep the
+ * pulse and space widths as clock cycles.  As this is CPU speed
+ * dependent, the widths must be calculated in init_port and ioctl
+ * time
+ */
+
+/* So send_pulse can quickly convert microseconds to clocks */
+static unsigned long conv_us_to_clocks;
+
+static int init_timing_params(unsigned int new_duty_cycle,
+               unsigned int new_freq)
+{
+       unsigned long long loops_per_sec, work;
+
+       duty_cycle = new_duty_cycle;
+       freq = new_freq;
+
+       loops_per_sec = current_cpu_data.loops_per_jiffy;
+       loops_per_sec *= HZ;
+
+       /* How many clocks in a microsecond?, avoiding long long divide */
+       work = loops_per_sec;
+       work *= 4295;  /* 4295 = 2^32 / 1e6 */
+       conv_us_to_clocks = (work >> 32);
+
+       /*
+        * Carrier period in clocks, approach good up to 32GHz clock,
+        * gets carrier frequency within 8Hz
+        */
+       period = loops_per_sec >> 3;
+       period /= (freq >> 3);
+
+       /* Derive pulse and space from the period */
+       pulse_width = period * duty_cycle / 100;
+       space_width = period - pulse_width;
+       dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
+               "clk/jiffy=%ld, pulse=%ld, space=%ld, "
+               "conv_us_to_clocks=%ld\n",
+               freq, duty_cycle, current_cpu_data.loops_per_jiffy,
+               pulse_width, space_width, conv_us_to_clocks);
+       return 0;
+}
+#else /* ! USE_RDTSC */
+static int init_timing_params(unsigned int new_duty_cycle,
+               unsigned int new_freq)
+{
+/*
+ * period, pulse/space width are kept with 8 binary places -
+ * IE multiplied by 256.
+ */
+       if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
+           LIRC_SERIAL_TRANSMITTER_LATENCY)
+               return -EINVAL;
+       if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
+           LIRC_SERIAL_TRANSMITTER_LATENCY)
+               return -EINVAL;
+       duty_cycle = new_duty_cycle;
+       freq = new_freq;
+       period = 256 * 1000000L / freq;
+       pulse_width = period * duty_cycle / 100;
+       space_width = period - pulse_width;
+       dprintk("in init_timing_params, freq=%d pulse=%ld, "
+               "space=%ld\n", freq, pulse_width, space_width);
+       return 0;
+}
+#endif /* USE_RDTSC */
+
+
+/* return value: space length delta */
+
+static long send_pulse_irdeo(unsigned long length)
+{
+       long rawbits, ret;
+       int i;
+       unsigned char output;
+       unsigned char chunk, shifted;
+
+       /* how many bits have to be sent ? */
+       rawbits = length * 1152 / 10000;
+       if (duty_cycle > 50)
+               chunk = 3;
+       else
+               chunk = 1;
+       for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) {
+               shifted = chunk << (i * 3);
+               shifted >>= 1;
+               output &= (~shifted);
+               i++;
+               if (i == 3) {
+                       soutp(UART_TX, output);
+                       while (!(sinp(UART_LSR) & UART_LSR_THRE))
+                               ;
+                       output = 0x7f;
+                       i = 0;
+               }
+       }
+       if (i != 0) {
+               soutp(UART_TX, output);
+               while (!(sinp(UART_LSR) & UART_LSR_TEMT))
+                       ;
+       }
+
+       if (i == 0)
+               ret = (-rawbits) * 10000 / 1152;
+       else
+               ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152;
+
+       return ret;
+}
+
+#ifdef USE_RDTSC
+/* Version that uses Pentium rdtsc instruction to measure clocks */
+
+/*
+ * This version does sub-microsecond timing using rdtsc instruction,
+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY
+ * Implicitly i586 architecture...  - Steve
+ */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+       int flag;
+       unsigned long target, start, now;
+
+       /* Get going quick as we can */
+       rdtscl(start);
+       on();
+       /* Convert length from microseconds to clocks */
+       length *= conv_us_to_clocks;
+       /* And loop till time is up - flipping at right intervals */
+       now = start;
+       target = pulse_width;
+       flag = 1;
+       /*
+        * FIXME: This looks like a hard busy wait, without even an occasional,
+        * polite, cpu_relax() call.  There's got to be a better way?
+        *
+        * The i2c code has the result of a lot of bit-banging work, I wonder if
+        * there's something there which could be helpful here.
+        */
+       while ((now - start) < length) {
+               /* Delay till flip time */
+               do {
+                       rdtscl(now);
+               } while ((now - start) < target);
+
+               /* flip */
+               if (flag) {
+                       rdtscl(now);
+                       off();
+                       target += space_width;
+               } else {
+                       rdtscl(now); on();
+                       target += pulse_width;
+               }
+               flag = !flag;
+       }
+       rdtscl(now);
+       return ((now - start) - length) / conv_us_to_clocks;
+}
+#else /* ! USE_RDTSC */
+/* Version using udelay() */
+
+/*
+ * here we use fixed point arithmetic, with 8
+ * fractional bits.  that gets us within 0.1% or so of the right average
+ * frequency, albeit with some jitter in pulse length - Steve
+ */
+
+/* To match 8 fractional bits used for pulse/space length */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+       int flag;
+       unsigned long actual, target, d;
+       length <<= 8;
+
+       actual = 0; target = 0; flag = 0;
+       while (actual < length) {
+               if (flag) {
+                       off();
+                       target += space_width;
+               } else {
+                       on();
+                       target += pulse_width;
+               }
+               d = (target - actual -
+                    LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8;
+               /*
+                * Note - we've checked in ioctl that the pulse/space
+                * widths are big enough so that d is > 0
+                */
+               udelay(d);
+               actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY;
+               flag = !flag;
+       }
+       return (actual-length) >> 8;
+}
+#endif /* USE_RDTSC */
+
+static long send_pulse_homebrew(unsigned long length)
+{
+       if (length <= 0)
+               return 0;
+
+       if (softcarrier)
+               return send_pulse_homebrew_softcarrier(length);
+       else {
+               on();
+               safe_udelay(length);
+               return 0;
+       }
+}
+
+static void send_space_irdeo(long length)
+{
+       if (length <= 0)
+               return;
+
+       safe_udelay(length);
+}
+
+static void send_space_homebrew(long length)
+{
+       off();
+       if (length <= 0)
+               return;
+       safe_udelay(length);
+}
+
+static void rbwrite(int l)
+{
+       if (lirc_buffer_full(&rbuf)) {
+               /* no new signals will be accepted */
+               dprintk("Buffer overrun\n");
+               return;
+       }
+       lirc_buffer_write(&rbuf, (void *)&l);
+}
+
+static void frbwrite(int l)
+{
+       /* simple noise filter */
+       static int pulse, space;
+       static unsigned int ptr;
+
+       if (ptr > 0 && (l & PULSE_BIT)) {
+               pulse += l & PULSE_MASK;
+               if (pulse > 250) {
+                       rbwrite(space);
+                       rbwrite(pulse | PULSE_BIT);
+                       ptr = 0;
+                       pulse = 0;
+               }
+               return;
+       }
+       if (!(l & PULSE_BIT)) {
+               if (ptr == 0) {
+                       if (l > 20000) {
+                               space = l;
+                               ptr++;
+                               return;
+                       }
+               } else {
+                       if (l > 20000) {
+                               space += pulse;
+                               if (space > PULSE_MASK)
+                                       space = PULSE_MASK;
+                               space += l;
+                               if (space > PULSE_MASK)
+                                       space = PULSE_MASK;
+                               pulse = 0;
+                               return;
+                       }
+                       rbwrite(space);
+                       rbwrite(pulse | PULSE_BIT);
+                       ptr = 0;
+                       pulse = 0;
+               }
+       }
+       rbwrite(l);
+}
+
+static irqreturn_t irq_handler(int i, void *blah)
+{
+       struct timeval tv;
+       int counter, dcd;
+       u8 status;
+       long deltv;
+       int data;
+       static int last_dcd = -1;
+
+       if ((sinp(UART_IIR) & UART_IIR_NO_INT)) {
+               /* not our interrupt */
+               return IRQ_NONE;
+       }
+
+       counter = 0;
+       do {
+               counter++;
+               status = sinp(UART_MSR);
+               if (counter > RS_ISR_PASS_LIMIT) {
+                       printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: "
+                              "We're caught!\n");
+                       break;
+               }
+               if ((status & hardware[type].signal_pin_change)
+                   && sense != -1) {
+                       /* get current time */
+                       do_gettimeofday(&tv);
+
+                       /* New mode, written by Trent Piepho
+                          <xyzzy@u.washington.edu>. */
+
+                       /*
+                        * The old format was not very portable.
+                        * We now use an int to pass pulses
+                        * and spaces to user space.
+                        *
+                        * If PULSE_BIT is set a pulse has been
+                        * received, otherwise a space has been
+                        * received.  The driver needs to know if your
+                        * receiver is active high or active low, or
+                        * the space/pulse sense could be
+                        * inverted. The bits denoted by PULSE_MASK are
+                        * the length in microseconds. Lengths greater
+                        * than or equal to 16 seconds are clamped to
+                        * PULSE_MASK.  All other bits are unused.
+                        * This is a much simpler interface for user
+                        * programs, as well as eliminating "out of
+                        * phase" errors with space/pulse
+                        * autodetection.
+                        */
+
+                       /* calc time since last interrupt in microseconds */
+                       dcd = (status & hardware[type].signal_pin) ? 1 : 0;
+
+                       if (dcd == last_dcd) {
+                               printk(KERN_WARNING LIRC_DRIVER_NAME
+                               ": ignoring spike: %d %d %lx %lx %lx %lx\n",
+                               dcd, sense,
+                               tv.tv_sec, lasttv.tv_sec,
+                               tv.tv_usec, lasttv.tv_usec);
+                               continue;
+                       }
+
+                       deltv = tv.tv_sec-lasttv.tv_sec;
+                       if (tv.tv_sec < lasttv.tv_sec ||
+                           (tv.tv_sec == lasttv.tv_sec &&
+                            tv.tv_usec < lasttv.tv_usec)) {
+                               printk(KERN_WARNING LIRC_DRIVER_NAME
+                                      ": AIEEEE: your clock just jumped "
+                                      "backwards\n");
+                               printk(KERN_WARNING LIRC_DRIVER_NAME
+                                      ": %d %d %lx %lx %lx %lx\n",
+                                      dcd, sense,
+                                      tv.tv_sec, lasttv.tv_sec,
+                                      tv.tv_usec, lasttv.tv_usec);
+                               data = PULSE_MASK;
+                       } else if (deltv > 15) {
+                               data = PULSE_MASK; /* really long time */
+                               if (!(dcd^sense)) {
+                                       /* sanity check */
+                                       printk(KERN_WARNING LIRC_DRIVER_NAME
+                                              ": AIEEEE: "
+                                              "%d %d %lx %lx %lx %lx\n",
+                                              dcd, sense,
+                                              tv.tv_sec, lasttv.tv_sec,
+                                              tv.tv_usec, lasttv.tv_usec);
+                                       /*
+                                        * detecting pulse while this
+                                        * MUST be a space!
+                                        */
+                                       sense = sense ? 0 : 1;
+                               }
+                       } else
+                               data = (int) (deltv*1000000 +
+                                              tv.tv_usec -
+                                              lasttv.tv_usec);
+                       frbwrite(dcd^sense ? data : (data|PULSE_BIT));
+                       lasttv = tv;
+                       last_dcd = dcd;
+                       wake_up_interruptible(&rbuf.wait_poll);
+               }
+       } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
+       return IRQ_HANDLED;
+}
+
+
+static int hardware_init_port(void)
+{
+       u8 scratch, scratch2, scratch3;
+
+       /*
+        * This is a simple port existence test, borrowed from the autoconfig
+        * function in drivers/serial/8250.c
+        */
+       scratch = sinp(UART_IER);
+       soutp(UART_IER, 0);
+#ifdef __i386__
+       outb(0xff, 0x080);
+#endif
+       scratch2 = sinp(UART_IER) & 0x0f;
+       soutp(UART_IER, 0x0f);
+#ifdef __i386__
+       outb(0x00, 0x080);
+#endif
+       scratch3 = sinp(UART_IER) & 0x0f;
+       soutp(UART_IER, scratch);
+       if (scratch2 != 0 || scratch3 != 0x0f) {
+               /* we fail, there's nothing here */
+               printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test "
+                      "failed, cannot continue\n");
+               return -EINVAL;
+       }
+
+
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* First of all, disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+       /* Clear registers. */
+       sinp(UART_LSR);
+       sinp(UART_RX);
+       sinp(UART_IIR);
+       sinp(UART_MSR);
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       if (type == LIRC_NSLU2) {
+               /* Setup NSLU2 UART */
+
+               /* Enable UART */
+               soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE);
+               /* Disable Receiver data Time out interrupt */
+               soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE);
+               /* set out2 = interrupt unmask; off() doesn't set MCR
+                  on NSLU2 */
+               soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       }
+#endif
+
+       /* Set line for power source */
+       off();
+
+       /* Clear registers again to be sure. */
+       sinp(UART_LSR);
+       sinp(UART_RX);
+       sinp(UART_IIR);
+       sinp(UART_MSR);
+
+       switch (type) {
+       case LIRC_IRDEO:
+       case LIRC_IRDEO_REMOTE:
+               /* setup port to 7N1 @ 115200 Baud */
+               /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */
+
+               /* Set DLAB 1. */
+               soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+               /* Set divisor to 1 => 115200 Baud */
+               soutp(UART_DLM, 0);
+               soutp(UART_DLL, 1);
+               /* Set DLAB 0 +  7N1 */
+               soutp(UART_LCR, UART_LCR_WLEN7);
+               /* THR interrupt already disabled at this point */
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int init_port(void)
+{
+       int i, nlow, nhigh;
+
+       /* Reserve io region. */
+       /*
+        * Future MMAP-Developers: Attention!
+        * For memory mapped I/O you *might* need to use ioremap() first,
+        * for the NSLU2 it's done in boot code.
+        */
+       if (((iommap != 0)
+            && (request_mem_region(iommap, 8 << ioshift,
+                                   LIRC_DRIVER_NAME) == NULL))
+          || ((iommap == 0)
+              && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) {
+               printk(KERN_ERR  LIRC_DRIVER_NAME
+                      ": port %04x already in use\n", io);
+               printk(KERN_WARNING LIRC_DRIVER_NAME
+                      ": use 'setserial /dev/ttySX uart none'\n");
+               printk(KERN_WARNING LIRC_DRIVER_NAME
+                      ": or compile the serial port driver as module and\n");
+               printk(KERN_WARNING LIRC_DRIVER_NAME
+                      ": make sure this module is loaded first\n");
+               return -EBUSY;
+       }
+
+       if (hardware_init_port() < 0)
+               return -EINVAL;
+
+       /* Initialize pulse/space widths */
+       init_timing_params(duty_cycle, freq);
+
+       /* If pin is high, then this must be an active low receiver. */
+       if (sense == -1) {
+               /* wait 1/2 sec for the power supply */
+               msleep(500);
+
+               /*
+                * probe 9 times every 0.04s, collect "votes" for
+                * active high/low
+                */
+               nlow = 0;
+               nhigh = 0;
+               for (i = 0; i < 9; i++) {
+                       if (sinp(UART_MSR) & hardware[type].signal_pin)
+                               nlow++;
+                       else
+                               nhigh++;
+                       msleep(40);
+               }
+               sense = (nlow >= nhigh ? 1 : 0);
+               printk(KERN_INFO LIRC_DRIVER_NAME  ": auto-detected active "
+                      "%s receiver\n", sense ? "low" : "high");
+       } else
+               printk(KERN_INFO LIRC_DRIVER_NAME  ": Manually using active "
+                      "%s receiver\n", sense ? "low" : "high");
+
+       return 0;
+}
+
+static int set_use_inc(void *data)
+{
+       int result;
+       unsigned long flags;
+
+       /* initialize timestamp */
+       do_gettimeofday(&lasttv);
+
+       result = request_irq(irq, irq_handler,
+                            IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0),
+                            LIRC_DRIVER_NAME, (void *)&hardware);
+
+       switch (result) {
+       case -EBUSY:
+               printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
+               return -EBUSY;
+       case -EINVAL:
+               printk(KERN_ERR LIRC_DRIVER_NAME
+                      ": Bad irq number or handler\n");
+               return -EINVAL;
+       default:
+               dprintk("Interrupt %d, port %04x obtained\n", irq, io);
+               break;
+       };
+
+       spin_lock_irqsave(&hardware[type].lock, flags);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{      unsigned long flags;
+
+       spin_lock_irqsave(&hardware[type].lock, flags);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* First of all, disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+       free_irq(irq, (void *)&hardware);
+
+       dprintk("freed IRQ %d\n", irq);
+}
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+                        size_t n, loff_t *ppos)
+{
+       int i, count;
+       unsigned long flags;
+       long delta = 0;
+       int *wbuf;
+
+       if (!(hardware[type].features & LIRC_CAN_SEND_PULSE))
+               return -EBADF;
+
+       count = n / sizeof(int);
+       if (n % sizeof(int) || count % 2 == 0)
+               return -EINVAL;
+       wbuf = memdup_user(buf, n);
+       if (PTR_ERR(wbuf))
+               return PTR_ERR(wbuf);
+       spin_lock_irqsave(&hardware[type].lock, flags);
+       if (type == LIRC_IRDEO) {
+               /* DTR, RTS down */
+               on();
+       }
+       for (i = 0; i < count; i++) {
+               if (i%2)
+                       hardware[type].send_space(wbuf[i] - delta);
+               else
+                       delta = hardware[type].send_pulse(wbuf[i]);
+       }
+       off();
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+       return n;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int result;
+       unsigned long value;
+       unsigned int ivalue;
+
+       switch (cmd) {
+       case LIRC_GET_SEND_MODE:
+               if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+                       return -ENOIOCTLCMD;
+
+               result = put_user(LIRC_SEND2MODE
+                                 (hardware[type].features&LIRC_CAN_SEND_MASK),
+                                 (unsigned long *) arg);
+               if (result)
+                       return result;
+               break;
+
+       case LIRC_SET_SEND_MODE:
+               if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+                       return -ENOIOCTLCMD;
+
+               result = get_user(value, (unsigned long *) arg);
+               if (result)
+                       return result;
+               /* only LIRC_MODE_PULSE supported */
+               if (value != LIRC_MODE_PULSE)
+                       return -ENOSYS;
+               break;
+
+       case LIRC_GET_LENGTH:
+               return -ENOSYS;
+               break;
+
+       case LIRC_SET_SEND_DUTY_CYCLE:
+               dprintk("SET_SEND_DUTY_CYCLE\n");
+               if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
+                       return -ENOIOCTLCMD;
+
+               result = get_user(ivalue, (unsigned int *) arg);
+               if (result)
+                       return result;
+               if (ivalue <= 0 || ivalue > 100)
+                       return -EINVAL;
+               return init_timing_params(ivalue, freq);
+               break;
+
+       case LIRC_SET_SEND_CARRIER:
+               dprintk("SET_SEND_CARRIER\n");
+               if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
+                       return -ENOIOCTLCMD;
+
+               result = get_user(ivalue, (unsigned int *) arg);
+               if (result)
+                       return result;
+               if (ivalue > 500000 || ivalue < 20000)
+                       return -EINVAL;
+               return init_timing_params(duty_cycle, ivalue);
+               break;
+
+       default:
+               return lirc_dev_fop_ioctl(filep, cmd, arg);
+       }
+       return 0;
+}
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .write          = lirc_write,
+       .unlocked_ioctl = lirc_ioctl,
+       .read           = lirc_dev_fop_read,
+       .poll           = lirc_dev_fop_poll,
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+};
+
+static struct lirc_driver driver = {
+       .name           = LIRC_DRIVER_NAME,
+       .minor          = -1,
+       .code_length    = 1,
+       .sample_rate    = 0,
+       .data           = NULL,
+       .add_to_buf     = NULL,
+       .rbuf           = &rbuf,
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .fops           = &lirc_fops,
+       .dev            = NULL,
+       .owner          = THIS_MODULE,
+};
+
+static struct platform_device *lirc_serial_dev;
+
+static int __devinit lirc_serial_probe(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int __devexit lirc_serial_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int lirc_serial_suspend(struct platform_device *dev,
+                              pm_message_t state)
+{
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* Disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+       /* Clear registers. */
+       sinp(UART_LSR);
+       sinp(UART_RX);
+       sinp(UART_IIR);
+       sinp(UART_MSR);
+
+       return 0;
+}
+
+/* twisty maze... need a forward-declaration here... */
+static void lirc_serial_exit(void);
+
+static int lirc_serial_resume(struct platform_device *dev)
+{
+       unsigned long flags;
+
+       if (hardware_init_port() < 0) {
+               lirc_serial_exit();
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&hardware[type].lock, flags);
+       /* Enable Interrupt */
+       do_gettimeofday(&lasttv);
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+       off();
+
+       lirc_buffer_clear(&rbuf);
+
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+       return 0;
+}
+
+static struct platform_driver lirc_serial_driver = {
+       .probe          = lirc_serial_probe,
+       .remove         = __devexit_p(lirc_serial_remove),
+       .suspend        = lirc_serial_suspend,
+       .resume         = lirc_serial_resume,
+       .driver         = {
+               .name   = "lirc_serial",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init lirc_serial_init(void)
+{
+       int result;
+
+       /* Init read buffer. */
+       result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+       if (result < 0)
+               return -ENOMEM;
+
+       result = platform_driver_register(&lirc_serial_driver);
+       if (result) {
+               printk("lirc register returned %d\n", result);
+               goto exit_buffer_free;
+       }
+
+       lirc_serial_dev = platform_device_alloc("lirc_serial", 0);
+       if (!lirc_serial_dev) {
+               result = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       result = platform_device_add(lirc_serial_dev);
+       if (result)
+               goto exit_device_put;
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(lirc_serial_dev);
+exit_driver_unregister:
+       platform_driver_unregister(&lirc_serial_driver);
+exit_buffer_free:
+       lirc_buffer_free(&rbuf);
+       return result;
+}
+
+static void lirc_serial_exit(void)
+{
+       platform_device_unregister(lirc_serial_dev);
+       platform_driver_unregister(&lirc_serial_driver);
+       lirc_buffer_free(&rbuf);
+}
+
+static int __init lirc_serial_init_module(void)
+{
+       int result;
+
+       result = lirc_serial_init();
+       if (result)
+               return result;
+
+       switch (type) {
+       case LIRC_HOMEBREW:
+       case LIRC_IRDEO:
+       case LIRC_IRDEO_REMOTE:
+       case LIRC_ANIMAX:
+       case LIRC_IGOR:
+               /* if nothing specified, use ttyS0/com1 and irq 4 */
+               io = io ? io : 0x3f8;
+               irq = irq ? irq : 4;
+               break;
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       case LIRC_NSLU2:
+               io = io ? io : IRQ_IXP4XX_UART2;
+               irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET);
+               iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS;
+               ioshift = ioshift ? ioshift : 2;
+               break;
+#endif
+       default:
+               result = -EINVAL;
+               goto exit_serial_exit;
+       }
+       if (!softcarrier) {
+               switch (type) {
+               case LIRC_HOMEBREW:
+               case LIRC_IGOR:
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+               case LIRC_NSLU2:
+#endif
+                       hardware[type].features &=
+                               ~(LIRC_CAN_SET_SEND_DUTY_CYCLE|
+                                 LIRC_CAN_SET_SEND_CARRIER);
+                       break;
+               }
+       }
+
+       result = init_port();
+       if (result < 0)
+               goto exit_serial_exit;
+       driver.features = hardware[type].features;
+       driver.dev = &lirc_serial_dev->dev;
+       driver.minor = lirc_register_driver(&driver);
+       if (driver.minor < 0) {
+               printk(KERN_ERR  LIRC_DRIVER_NAME
+                      ": register_chrdev failed!\n");
+               result = -EIO;
+               goto exit_release;
+       }
+       return 0;
+exit_release:
+       release_region(io, 8);
+exit_serial_exit:
+       lirc_serial_exit();
+       return result;
+}
+
+static void __exit lirc_serial_exit_module(void)
+{
+       lirc_serial_exit();
+       if (iommap != 0)
+               release_mem_region(iommap, 8 << ioshift);
+       else
+               release_region(io, 8);
+       lirc_unregister_driver(driver.minor);
+       dprintk("cleaned up module\n");
+}
+
+
+module_init(lirc_serial_init_module);
+module_exit(lirc_serial_exit_module);
+
+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports.");
+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, "
+             "Christoph Bartelmus, Andrei Tanas");
+MODULE_LICENSE("GPL");
+
+module_param(type, int, S_IRUGO);
+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo,"
+                " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug,"
+                " 5 = NSLU2 RX:CTS2/TX:GreenLED)");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+/* some architectures (e.g. intel xscale) have memory mapped registers */
+module_param(iommap, bool, S_IRUGO);
+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O"
+               " (0 = no memory mapped io)");
+
+/*
+ * some architectures (e.g. intel xscale) align the 8bit serial registers
+ * on 32bit word boundaries.
+ * See linux-kernel/serial/8250.c serial_in()/out()
+ */
+module_param(ioshift, int, S_IRUGO);
+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(share_irq, bool, S_IRUGO);
+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)");
+
+module_param(sense, bool, S_IRUGO);
+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
+                " (0 = active high, 1 = active low )");
+
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+module_param(txsense, bool, S_IRUGO);
+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit"
+                " (0 = active high, 1 = active low )");
+#endif
+
+module_param(softcarrier, bool, S_IRUGO);
+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c
new file mode 100644 (file)
index 0000000..eb08fa7
--- /dev/null
@@ -0,0 +1,1282 @@
+/*
+ * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
+ *
+ * lirc_sir - Device driver for use with SIR (serial infra red)
+ * mode of IrDA on many notebooks.
+ *
+ *  This program is free software; 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
+ *
+ *
+ * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> :
+ *  added timeout and relaxed pulse detection, removed gap bug
+ *
+ * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   added support for Tekram Irmate 210 (sending does not work yet,
+ *   kind of disappointing that nobody was able to implement that
+ *   before),
+ *   major clean-up
+ *
+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   added support for StrongARM SA1100 embedded microprocessor
+ *   parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King
+ */
+
+#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/serial_reg.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 <asm/irq.h>
+#include <linux/fcntl.h>
+#ifdef LIRC_ON_SA1100
+#include <asm/hardware.h>
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/tc35143.h>
+#include <asm/ucb1200.h>
+#endif
+#endif
+
+#include <linux/timer.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* SECTION: Definitions */
+
+/*** Tekram dongle ***/
+#ifdef LIRC_SIR_TEKRAM
+/* stolen from kernel source */
+/* definitions for Tekram dongle */
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600  0x01
+#define TEKRAM_38400  0x02
+#define TEKRAM_19200  0x03
+#define TEKRAM_9600   0x04
+#define TEKRAM_2400   0x08
+
+#define TEKRAM_PW 0x10 /* Pulse select bit */
+
+/* 10bit * 1s/115200bit in milliseconds = 87ms*/
+#define TIME_CONST (10000000ul/115200ul)
+
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+static void init_act200(void);
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+static void init_act220(void);
+#endif
+
+/*** SA1100 ***/
+#ifdef LIRC_ON_SA1100
+struct sa1100_ser2_registers {
+       /* HSSP control register */
+       unsigned char hscr0;
+       /* UART registers */
+       unsigned char utcr0;
+       unsigned char utcr1;
+       unsigned char utcr2;
+       unsigned char utcr3;
+       unsigned char utcr4;
+       unsigned char utdr;
+       unsigned char utsr0;
+       unsigned char utsr1;
+} sr;
+
+static int irq = IRQ_Ser2ICP;
+
+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0
+
+/* pulse/space ratio of 50/50 */
+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+/* 1000000/freq-pulse_width */
+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+static unsigned int freq = 38000;      /* modulation frequency */
+static unsigned int duty_cycle = 50;   /* duty cycle of 50% */
+
+#endif
+
+#define RBUF_LEN 1024
+#define WBUF_LEN 1024
+
+#define LIRC_DRIVER_NAME "lirc_sir"
+
+#define PULSE '['
+
+#ifndef LIRC_SIR_TEKRAM
+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/
+#define TIME_CONST (9000000ul/115200ul)
+#endif
+
+
+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */
+#define SIR_TIMEOUT    (HZ*5/100)
+
+#ifndef LIRC_ON_SA1100
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 4
+#endif
+#ifndef LIRC_PORT
+/* for external dongles, default to com1 */
+#if defined(LIRC_SIR_ACTISYS_ACT200L) || \
+    defined(LIRC_SIR_ACTISYS_ACT220L) || \
+    defined(LIRC_SIR_TEKRAM)
+#define LIRC_PORT 0x3f8
+#else
+/* onboard sir ports are typically com3 */
+#define LIRC_PORT 0x3e8
+#endif
+#endif
+
+static int io = LIRC_PORT;
+static int irq = LIRC_IRQ;
+static int threshold = 3;
+#endif
+
+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 int rx_buf[RBUF_LEN];
+static unsigned int rx_tail, rx_head;
+
+static int debug;
+#define dprintk(fmt, args...)                                          \
+       do {                                                            \
+               if (debug)                                              \
+                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": "         \
+                               fmt, ## args);                          \
+       } while (0)
+
+/* SECTION: Prototypes */
+
+/* Communication with user-space */
+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 sir_interrupt(int irq, void *dev_id);
+static void send_space(unsigned long len);
+static void send_pulse(unsigned long len);
+static int init_hardware(void);
+static void drop_hardware(void);
+/* Initialisation */
+static int init_port(void);
+static void drop_port(void);
+
+#ifdef LIRC_ON_SA1100
+static void on(void)
+{
+       PPSR |= PPC_TXD2;
+}
+
+static void off(void)
+{
+       PPSR &= ~PPC_TXD2;
+}
+#else
+static inline unsigned int sinp(int offset)
+{
+       return inb(io + offset);
+}
+
+static inline void soutp(int offset, int value)
+{
+       outb(value, io + offset);
+}
+#endif
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+       while (usecs > MAX_UDELAY_US) {
+               udelay(MAX_UDELAY_US);
+               usecs -= MAX_UDELAY_US;
+       }
+       udelay(usecs);
+}
+
+/* SECTION: Communication with user-space */
+
+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;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (count % sizeof(int))
+               return -EINVAL;
+
+       add_wait_queue(&lirc_read_queue, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (n < count) {
+               if (rx_head != rx_tail) {
+                       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);
+               } else {
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+       }
+       remove_wait_queue(&lirc_read_queue, &wait);
+       set_current_state(TASK_RUNNING);
+       return n ? n : retval;
+}
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+                               loff_t *pos)
+{
+       unsigned long flags;
+       int i, count;
+       int *tx_buf;
+
+       count = n / sizeof(int);
+       if (n % sizeof(int) || count % 2 == 0)
+               return -EINVAL;
+       tx_buf = memdup_user(buf, n);
+       if (IS_ERR(tx_buf))
+               return PTR_ERR(tx_buf);
+       i = 0;
+#ifdef LIRC_ON_SA1100
+       /* disable receiver */
+       Ser2UTCR3 = 0;
+#endif
+       local_irq_save(flags);
+       while (1) {
+               if (i >= count)
+                       break;
+               if (tx_buf[i])
+                       send_pulse(tx_buf[i]);
+               i++;
+               if (i >= count)
+                       break;
+               if (tx_buf[i])
+                       send_space(tx_buf[i]);
+               i++;
+       }
+       local_irq_restore(flags);
+#ifdef LIRC_ON_SA1100
+       off();
+       udelay(1000); /* wait 1ms for IR diode to recover */
+       Ser2UTCR3 = 0;
+       /* clear status register to prevent unwanted interrupts */
+       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+       /* enable receiver */
+       Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+#endif
+       return count;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int retval = 0;
+       unsigned long value = 0;
+#ifdef LIRC_ON_SA1100
+       unsigned int ivalue;
+
+       if (cmd == LIRC_GET_FEATURES)
+               value = LIRC_CAN_SEND_PULSE |
+                       LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                       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;
+#else
+       if (cmd == LIRC_GET_FEATURES)
+               value = LIRC_CAN_SEND_PULSE | 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;
+#endif
+
+       switch (cmd) {
+       case LIRC_GET_FEATURES:
+       case LIRC_GET_SEND_MODE:
+       case LIRC_GET_REC_MODE:
+               retval = put_user(value, (unsigned long *) arg);
+               break;
+
+       case LIRC_SET_SEND_MODE:
+       case LIRC_SET_REC_MODE:
+               retval = get_user(value, (unsigned long *) arg);
+               break;
+#ifdef LIRC_ON_SA1100
+       case LIRC_SET_SEND_DUTY_CYCLE:
+               retval = get_user(ivalue, (unsigned int *) arg);
+               if (retval)
+                       return retval;
+               if (ivalue <= 0 || ivalue > 100)
+                       return -EINVAL;
+               /* (ivalue/100)*(1000000/freq) */
+               duty_cycle = ivalue;
+               pulse_width = (unsigned long) duty_cycle*10000/freq;
+               space_width = (unsigned long) 1000000L/freq-pulse_width;
+               if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               break;
+       case LIRC_SET_SEND_CARRIER:
+               retval = get_user(ivalue, (unsigned int *) arg);
+               if (retval)
+                       return retval;
+               if (ivalue > 500000 || ivalue < 20000)
+                       return -EINVAL;
+               freq = ivalue;
+               pulse_width = (unsigned long) duty_cycle*10000/freq;
+               space_width = (unsigned long) 1000000L/freq-pulse_width;
+               if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               break;
+#endif
+       default:
+               retval = -ENOIOCTLCMD;
+
+       }
+
+       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,
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+};
+
+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 sir_timeout(unsigned long data)
+{
+       /*
+        * 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.
+        */
+
+       unsigned long flags;
+       unsigned long pulse_end;
+
+       /* avoid interference with interrupt */
+       spin_lock_irqsave(&timer_lock, flags);
+       if (last_value) {
+#ifndef LIRC_ON_SA1100
+               /* clear unread bits in UART and restart */
+               outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);
+#endif
+               /* 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 sir_interrupt(int irq, void *dev_id)
+{
+       unsigned char data;
+       struct timeval curr_tv;
+       static unsigned long deltv;
+#ifdef LIRC_ON_SA1100
+       int status;
+       static int n;
+
+       status = Ser2UTSR0;
+       /*
+        * Deal with any receive errors first.  The bytes in error may be
+        * the only bytes in the receive FIFO, so we do this first.
+        */
+       while (status & UTSR0_EIF) {
+               int bstat;
+
+               if (debug) {
+                       dprintk("EIF\n");
+                       bstat = Ser2UTSR1;
+
+                       if (bstat & UTSR1_FRE)
+                               dprintk("frame error\n");
+                       if (bstat & UTSR1_ROR)
+                               dprintk("receive fifo overrun\n");
+                       if (bstat & UTSR1_PRE)
+                               dprintk("parity error\n");
+               }
+
+               bstat = Ser2UTDR;
+               n++;
+               status = Ser2UTSR0;
+       }
+
+       if (status & (UTSR0_RFS | UTSR0_RID)) {
+               do_gettimeofday(&curr_tv);
+               deltv = delta(&last_tv, &curr_tv);
+               do {
+                       data = Ser2UTDR;
+                       dprintk("%d data: %u\n", n, (unsigned int) data);
+                       n++;
+               } while (status & UTSR0_RID && /* do not empty fifo in order to
+                                               * get UTSR0_RID in any case */
+                     Ser2UTSR1 & UTSR1_RNE); /* data ready */
+
+               if (status&UTSR0_RID) {
+                       add_read_queue(0 , deltv - n * TIME_CONST); /*space*/
+                       add_read_queue(1, n * TIME_CONST); /*pulse*/
+                       n = 0;
+                       last_tv = curr_tv;
+               }
+       }
+
+       if (status & UTSR0_TFS)
+               printk(KERN_ERR "transmit fifo not full, shouldn't happen\n");
+
+       /* We must clear certain bits. */
+       status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+       if (status)
+               Ser2UTSR0 = status;
+#else
+       unsigned long deltintrtv;
+       unsigned long flags;
+       int iir, lsr;
+
+       while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
+               switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */
+               case UART_IIR_MSI:
+                       (void) inb(io + UART_MSR);
+                       break;
+               case UART_IIR_RLSI:
+                       (void) inb(io + UART_LSR);
+                       break;
+               case UART_IIR_THRI:
+#if 0
+                       if (lsr & UART_LSR_THRE) /* FIFO is empty */
+                               outb(data, io + UART_TX)
+#endif
+                       break;
+               case UART_IIR_RDI:
+                       /* avoid interference with timer */
+                       spin_lock_irqsave(&timer_lock, flags);
+                       do {
+                               del_timer(&timerlist);
+                               data = inb(io + UART_RX);
+                               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 X cycles,
+                                * it was gap
+                                */
+                               if (deltintrtv > TIME_CONST * threshold) {
+                                       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 +
+                                                               SIR_TIMEOUT;
+                                       add_timer(&timerlist);
+                               }
+
+                               lsr = inb(io + UART_LSR);
+                       } while (lsr & UART_LSR_DR); /* data ready */
+                       spin_unlock_irqrestore(&timer_lock, flags);
+                       break;
+               default:
+                       break;
+               }
+       }
+#endif
+       return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+#ifdef LIRC_ON_SA1100
+static void send_pulse(unsigned long length)
+{
+       unsigned long k, delay;
+       int flag;
+
+       if (length == 0)
+               return;
+       /*
+        * this won't give us the carrier frequency we really want
+        * due to integer arithmetic, but we can accept this inaccuracy
+        */
+
+       for (k = flag = 0; k < length; k += delay, flag = !flag) {
+               if (flag) {
+                       off();
+                       delay = space_width;
+               } else {
+                       on();
+                       delay = pulse_width;
+               }
+               safe_udelay(delay);
+       }
+       off();
+}
+
+static void send_space(unsigned long length)
+{
+       if (length == 0)
+               return;
+       off();
+       safe_udelay(length);
+}
+#else
+static void send_space(unsigned long len)
+{
+       safe_udelay(len);
+}
+
+static void send_pulse(unsigned long len)
+{
+       long bytes_out = len / TIME_CONST;
+       long time_left;
+
+       time_left = (long)len - (long)bytes_out * (long)TIME_CONST;
+       if (bytes_out == 0) {
+               bytes_out++;
+               time_left = 0;
+       }
+       while (bytes_out--) {
+               outb(PULSE, io + UART_TX);
+               /* FIXME treba seriozne cakanie z char/serial.c */
+               while (!(inb(io + UART_LSR) & UART_LSR_THRE))
+                       ;
+       }
+#if 0
+       if (time_left > 0)
+               safe_udelay(time_left);
+#endif
+}
+#endif
+
+#ifdef CONFIG_SA1100_COLLIE
+static int sa1100_irda_set_power_collie(int state)
+{
+       if (state) {
+               /*
+                *  0 - off
+                *  1 - short range, lowest power
+                *  2 - medium range, medium power
+                *  3 - maximum range, high power
+                */
+               ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+                                        TC35143_IODIR_OUTPUT);
+               ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW);
+               udelay(100);
+       } else {
+               /* OFF */
+               ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+                                        TC35143_IODIR_OUTPUT);
+               ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH);
+       }
+       return 0;
+}
+#endif
+
+static int init_hardware(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hardware_lock, flags);
+       /* reset UART */
+#ifdef LIRC_ON_SA1100
+#ifdef CONFIG_SA1100_BITSY
+       if (machine_is_bitsy()) {
+               printk(KERN_INFO "Power on IR module\n");
+               set_bitsy_egpio(EGPIO_BITSY_IR_ON);
+       }
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+       sa1100_irda_set_power_collie(3);        /* power on */
+#endif
+       sr.hscr0 = Ser2HSCR0;
+
+       sr.utcr0 = Ser2UTCR0;
+       sr.utcr1 = Ser2UTCR1;
+       sr.utcr2 = Ser2UTCR2;
+       sr.utcr3 = Ser2UTCR3;
+       sr.utcr4 = Ser2UTCR4;
+
+       sr.utdr = Ser2UTDR;
+       sr.utsr0 = Ser2UTSR0;
+       sr.utsr1 = Ser2UTSR1;
+
+       /* configure GPIO */
+       /* output */
+       PPDR |= PPC_TXD2;
+       PSDR |= PPC_TXD2;
+       /* set output to 0 */
+       off();
+
+       /* Enable HP-SIR modulation, and ensure that the port is disabled. */
+       Ser2UTCR3 = 0;
+       Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP);
+
+       /* clear status register to prevent unwanted interrupts */
+       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+       /* 7N1 */
+       Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData;
+       /* 115200 */
+       Ser2UTCR1 = 0;
+       Ser2UTCR2 = 1;
+       /* use HPSIR, 1.6 usec pulses */
+       Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us;
+
+       /* enable receiver, receive fifo interrupt */
+       Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+
+       /* clear status register to prevent unwanted interrupts */
+       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+#elif defined(LIRC_SIR_TEKRAM)
+       /* disable FIFO */
+       soutp(UART_FCR,
+             UART_FCR_CLEAR_RCVR|
+             UART_FCR_CLEAR_XMIT|
+             UART_FCR_TRIGGER_1);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* First of all, disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+       /* Set divisor to 12 => 9600 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 12);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* power supply */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       safe_udelay(50*1000);
+
+       /* -DTR low -> reset PIC */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       udelay(1*1000);
+
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(100);
+
+
+       /* -RTS low -> send control byte */
+       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(7);
+       soutp(UART_TX, TEKRAM_115200|TEKRAM_PW);
+
+       /* one byte takes ~1042 usec to transmit at 9600,8N1 */
+       udelay(1500);
+
+       /* back to normal operation */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(50);
+
+       udelay(1500);
+
+       /* read previous control byte */
+       printk(KERN_INFO LIRC_DRIVER_NAME
+              ": 0x%02x\n", sinp(UART_RX));
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+       /* Set divisor to 1 => 115200 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 1);
+
+       /* Set DLAB 0, 8 Bit */
+       soutp(UART_LCR, UART_LCR_WLEN8);
+       /* enable interrupts */
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+#else
+       outb(0, io + UART_MCR);
+       outb(0, io + UART_IER);
+       /* init UART */
+       /* set DLAB, speed = 115200 */
+       outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR);
+       outb(1, io + UART_DLL); outb(0, io + UART_DLM);
+       /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */
+       outb(UART_LCR_WLEN7, io + UART_LCR);
+       /* FIFO operation */
+       outb(UART_FCR_ENABLE_FIFO, io + UART_FCR);
+       /* interrupts */
+       /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */
+       outb(UART_IER_RDI, io + UART_IER);
+       /* turn on UART */
+       outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR);
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+       init_act200();
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+       init_act220();
+#endif
+#endif
+       spin_unlock_irqrestore(&hardware_lock, flags);
+       return 0;
+}
+
+static void drop_hardware(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hardware_lock, flags);
+
+#ifdef LIRC_ON_SA1100
+       Ser2UTCR3 = 0;
+
+       Ser2UTCR0 = sr.utcr0;
+       Ser2UTCR1 = sr.utcr1;
+       Ser2UTCR2 = sr.utcr2;
+       Ser2UTCR4 = sr.utcr4;
+       Ser2UTCR3 = sr.utcr3;
+
+       Ser2HSCR0 = sr.hscr0;
+#ifdef CONFIG_SA1100_BITSY
+       if (machine_is_bitsy())
+               clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+       sa1100_irda_set_power_collie(0);        /* power off */
+#endif
+#else
+       /* turn off interrupts */
+       outb(0, io + UART_IER);
+#endif
+       spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+/* SECTION: Initialisation */
+
+static int init_port(void)
+{
+       int retval;
+
+       /* get I/O port access and IRQ line */
+#ifndef LIRC_ON_SA1100
+       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);
+               return -EBUSY;
+       }
+#endif
+       retval = request_irq(irq, sir_interrupt, IRQF_DISABLED,
+                            LIRC_DRIVER_NAME, NULL);
+       if (retval < 0) {
+#               ifndef LIRC_ON_SA1100
+               release_region(io, 8);
+#               endif
+               printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": IRQ %d already in use.\n",
+                       irq);
+               return retval;
+       }
+#ifndef LIRC_ON_SA1100
+       printk(KERN_INFO LIRC_DRIVER_NAME
+               ": I/O port 0x%.4x, IRQ %d.\n",
+               io, irq);
+#endif
+
+       init_timer(&timerlist);
+       timerlist.function = sir_timeout;
+       timerlist.data = 0xabadcafe;
+
+       return 0;
+}
+
+static void drop_port(void)
+{
+       free_irq(irq, NULL);
+       del_timer_sync(&timerlist);
+#ifndef LIRC_ON_SA1100
+       release_region(io, 8);
+#endif
+}
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */
+/* some code borrowed from Linux IRDA driver */
+
+/* Register 0: Control register #1 */
+#define ACT200L_REG0    0x00
+#define ACT200L_TXEN    0x01 /* Enable transmitter */
+#define ACT200L_RXEN    0x02 /* Enable receiver */
+#define ACT200L_ECHO    0x08 /* Echo control chars */
+
+/* Register 1: Control register #2 */
+#define ACT200L_REG1    0x10
+#define ACT200L_LODB    0x01 /* Load new baud rate count value */
+#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
+
+/* Register 3: Transmit mode register #2 */
+#define ACT200L_REG3    0x30
+#define ACT200L_B0      0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
+#define ACT200L_B1      0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
+#define ACT200L_CHSY    0x04 /* StartBit Synced 0=bittime, 1=startbit */
+
+/* Register 4: Output Power register */
+#define ACT200L_REG4    0x40
+#define ACT200L_OP0     0x01 /* Enable LED1C output */
+#define ACT200L_OP1     0x02 /* Enable LED2C output */
+#define ACT200L_BLKR    0x04
+
+/* Register 5: Receive Mode register */
+#define ACT200L_REG5    0x50
+#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
+    /*.. other various IRDA bit modes, and TV remote modes..*/
+
+/* Register 6: Receive Sensitivity register #1 */
+#define ACT200L_REG6    0x60
+#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
+#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
+
+/* Register 7: Receive Sensitivity register #2 */
+#define ACT200L_REG7    0x70
+#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
+
+/* Register 8,9: Baud Rate Divider register #1,#2 */
+#define ACT200L_REG8    0x80
+#define ACT200L_REG9    0x90
+
+#define ACT200L_2400    0x5f
+#define ACT200L_9600    0x17
+#define ACT200L_19200   0x0b
+#define ACT200L_38400   0x05
+#define ACT200L_57600   0x03
+#define ACT200L_115200  0x01
+
+/* Register 13: Control register #3 */
+#define ACT200L_REG13   0xd0
+#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
+
+/* Register 15: Status register */
+#define ACT200L_REG15   0xf0
+
+/* Register 21: Control register #4 */
+#define ACT200L_REG21   0x50
+#define ACT200L_EXCK    0x02 /* Disable clock output driver */
+#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
+
+static void init_act200(void)
+{
+       int i;
+       __u8 control[] = {
+               ACT200L_REG15,
+               ACT200L_REG13 | ACT200L_SHDW,
+               ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
+               ACT200L_REG13,
+               ACT200L_REG7  | ACT200L_ENPOS,
+               ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
+               ACT200L_REG5  | ACT200L_RWIDL,
+               ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
+               ACT200L_REG3  | ACT200L_B0,
+               ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN,
+               ACT200L_REG8 |  (ACT200L_115200       & 0x0f),
+               ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f),
+               ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE
+       };
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+
+       /* Set divisor to 12 => 9600 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 12);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, UART_LCR_WLEN8);
+       /* Set divisor to 12 => 9600 Baud */
+
+       /* power supply */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       for (i = 0; i < 50; i++)
+               safe_udelay(1000);
+
+               /* Reset the dongle : set RTS low for 25 ms */
+       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+       for (i = 0; i < 25; i++)
+               udelay(1000);
+
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(100);
+
+       /* Clear DTR and set RTS to enter command mode */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       udelay(7);
+
+       /* send out the control register settings for 115K 7N1 SIR operation */
+       for (i = 0; i < sizeof(control); i++) {
+               soutp(UART_TX, control[i]);
+               /* one byte takes ~1042 usec to transmit at 9600,8N1 */
+               udelay(1500);
+       }
+
+       /* back to normal operation */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(50);
+
+       udelay(1500);
+       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+       /* Set divisor to 1 => 115200 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 1);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* Set DLAB 0, 7 Bit */
+       soutp(UART_LCR, UART_LCR_WLEN7);
+
+       /* enable interrupts */
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+}
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT220L
+/*
+ * Derived from linux IrDA driver (net/irda/actisys.c)
+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net
+ */
+
+void init_act220(void)
+{
+       int i;
+
+       /* DLAB 1 */
+       soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7);
+
+       /* 9600 baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 12);
+
+       /* DLAB 0 */
+       soutp(UART_LCR, UART_LCR_WLEN7);
+
+       /* reset the dongle, set DTR low for 10us */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       udelay(10);
+
+       /* back to normal (still 9600) */
+       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2);
+
+       /*
+        * send RTS pulses until we reach 115200
+        * i hope this is really the same for act220l/act220l+
+        */
+       for (i = 0; i < 3; i++) {
+               udelay(10);
+               /* set RTS low for 10 us */
+               soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+               udelay(10);
+               /* set RTS high for 10 us */
+               soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       }
+
+       /* back to normal operation */
+       udelay(1500); /* better safe than sorry ;) */
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+       /* Set divisor to 1 => 115200 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 1);
+
+       /* Set DLAB 0, 7 Bit */
+       /* The dongle doesn't seem to have any problems with operation at 7N1 */
+       soutp(UART_LCR, UART_LCR_WLEN7);
+
+       /* enable interrupts */
+       soutp(UART_IER, UART_IER_RDI);
+}
+#endif
+
+static int init_lirc_sir(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 __init lirc_sir_init(void)
+{
+       int retval;
+
+       retval = init_chrdev();
+       if (retval < 0)
+               return retval;
+       retval = init_lirc_sir();
+       if (retval) {
+               drop_chrdev();
+               return retval;
+       }
+       return 0;
+}
+
+static void __exit lirc_sir_exit(void)
+{
+       drop_hardware();
+       drop_chrdev();
+       drop_port();
+       printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+}
+
+module_init(lirc_sir_init);
+module_exit(lirc_sir_exit);
+
+#ifdef LIRC_SIR_TEKRAM
+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_ON_SA1100)
+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_SIR_ACTISYS_ACT200L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L");
+MODULE_AUTHOR("Karl Bongers");
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)");
+MODULE_AUTHOR("Jan Roemisch");
+#else
+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
+MODULE_AUTHOR("Milan Pikula");
+#endif
+MODULE_LICENSE("GPL");
+
+#ifdef LIRC_ON_SA1100
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (16)");
+#else
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(threshold, int, S_IRUGO);
+MODULE_PARM_DESC(threshold, "space detection threshold (3)");
+#endif
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c
new file mode 100644 (file)
index 0000000..be09c10
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * Streamzap Remote Control driver
+ *
+ * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de>
+ *
+ * This driver was based on the work of Greg Wickham and Adrian
+ * Dewhurst. It was substantially rewritten to support correct signal
+ * gaps and now maintains a delay buffer, which is used to present
+ * consistent timing behaviour to user space applications. Without the
+ * delay buffer an ugly hack would be required in lircd, which can
+ * cause sluggish signal decoding in certain situations.
+ *
+ * This driver is based on the USB skeleton driver packaged with the
+ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.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/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define DRIVER_VERSION "1.28"
+#define DRIVER_NAME    "lirc_streamzap"
+#define DRIVER_DESC    "Streamzap Remote Control driver"
+
+static int debug;
+
+#define USB_STREAMZAP_VENDOR_ID                0x0e9c
+#define USB_STREAMZAP_PRODUCT_ID       0x0000
+
+/* Use our own dbg macro */
+#define dprintk(fmt, args...)                                  \
+       do {                                                    \
+               if (debug)                                      \
+                       printk(KERN_DEBUG DRIVER_NAME "[%d]: "  \
+                              fmt "\n", ## args);              \
+       } while (0)
+
+/* table of devices that work with this driver */
+static struct usb_device_id streamzap_table[] = {
+       /* Streamzap Remote Control */
+       { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) },
+       /* Terminating entry */
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, streamzap_table);
+
+#define STREAMZAP_PULSE_MASK 0xf0
+#define STREAMZAP_SPACE_MASK 0x0f
+#define STREAMZAP_TIMEOUT    0xff
+#define STREAMZAP_RESOLUTION 256
+
+/* number of samples buffered */
+#define STREAMZAP_BUF_LEN 128
+
+enum StreamzapDecoderState {
+       PulseSpace,
+       FullPulse,
+       FullSpace,
+       IgnorePulse
+};
+
+/* Structure to hold all of our device specific stuff
+ *
+ * some remarks regarding locking:
+ * theoretically this struct can be accessed from three threads:
+ *
+ * - from lirc_dev through set_use_inc/set_use_dec
+ *
+ * - from the USB layer throuh probe/disconnect/irq
+ *
+ *   Careful placement of lirc_register_driver/lirc_unregister_driver
+ *   calls will prevent conflicts. lirc_dev makes sure that
+ *   set_use_inc/set_use_dec are not being executed and will not be
+ *   called after lirc_unregister_driver returns.
+ *
+ * - by the timer callback
+ *
+ *   The timer is only running when the device is connected and the
+ *   LIRC device is open. Making sure the timer is deleted by
+ *   set_use_dec will make conflicts impossible.
+ */
+struct usb_streamzap {
+
+       /* usb */
+       /* save off the usb device pointer */
+       struct usb_device       *udev;
+       /* the interface for this device */
+       struct usb_interface    *interface;
+
+       /* buffer & dma */
+       unsigned char           *buf_in;
+       dma_addr_t              dma_in;
+       unsigned int            buf_in_len;
+
+       struct usb_endpoint_descriptor *endpoint;
+
+       /* IRQ */
+       struct urb              *urb_in;
+
+       /* lirc */
+       struct lirc_driver      *driver;
+       struct lirc_buffer      *delay_buf;
+
+       /* timer used to support delay buffering */
+       struct timer_list       delay_timer;
+       int                     timer_running;
+       spinlock_t              timer_lock;
+
+       /* tracks whether we are currently receiving some signal */
+       int                     idle;
+       /* sum of signal lengths received since signal start */
+       unsigned long           sum;
+       /* start time of signal; necessary for gap tracking */
+       struct timeval          signal_last;
+       struct timeval          signal_start;
+       enum StreamzapDecoderState decoder_state;
+       struct timer_list       flush_timer;
+       int                     flush;
+       int                     in_use;
+       int                     timeout_enabled;
+};
+
+
+/* local function prototypes */
+static int streamzap_probe(struct usb_interface *interface,
+                          const struct usb_device_id *id);
+static void streamzap_disconnect(struct usb_interface *interface);
+static void usb_streamzap_irq(struct urb *urb);
+static int streamzap_use_inc(void *data);
+static void streamzap_use_dec(void *data);
+static long streamzap_ioctl(struct file *filep, unsigned int cmd,
+                           unsigned long arg);
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message);
+static int streamzap_resume(struct usb_interface *intf);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+
+static struct usb_driver streamzap_driver = {
+       .name =         DRIVER_NAME,
+       .probe =        streamzap_probe,
+       .disconnect =   streamzap_disconnect,
+       .suspend =      streamzap_suspend,
+       .resume =       streamzap_resume,
+       .id_table =     streamzap_table,
+};
+
+static void stop_timer(struct usb_streamzap *sz)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sz->timer_lock, flags);
+       if (sz->timer_running) {
+               sz->timer_running = 0;
+               spin_unlock_irqrestore(&sz->timer_lock, flags);
+               del_timer_sync(&sz->delay_timer);
+       } else {
+               spin_unlock_irqrestore(&sz->timer_lock, flags);
+       }
+}
+
+static void flush_timeout(unsigned long arg)
+{
+       struct usb_streamzap *sz = (struct usb_streamzap *) arg;
+
+       /* finally start accepting data */
+       sz->flush = 0;
+}
+static void delay_timeout(unsigned long arg)
+{
+       unsigned long flags;
+       /* deliver data every 10 ms */
+       static unsigned long timer_inc =
+               (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ));
+       struct usb_streamzap *sz = (struct usb_streamzap *) arg;
+       int data;
+
+       spin_lock_irqsave(&sz->timer_lock, flags);
+
+       if (!lirc_buffer_empty(sz->delay_buf) &&
+           !lirc_buffer_full(sz->driver->rbuf)) {
+               lirc_buffer_read(sz->delay_buf, (unsigned char *) &data);
+               lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data);
+       }
+       if (!lirc_buffer_empty(sz->delay_buf)) {
+               while (lirc_buffer_available(sz->delay_buf) <
+                      STREAMZAP_BUF_LEN / 2 &&
+                      !lirc_buffer_full(sz->driver->rbuf)) {
+                       lirc_buffer_read(sz->delay_buf,
+                                          (unsigned char *) &data);
+                       lirc_buffer_write(sz->driver->rbuf,
+                                           (unsigned char *) &data);
+               }
+               if (sz->timer_running) {
+                       sz->delay_timer.expires = jiffies + timer_inc;
+                       add_timer(&sz->delay_timer);
+               }
+       } else {
+               sz->timer_running = 0;
+       }
+
+       if (!lirc_buffer_empty(sz->driver->rbuf))
+               wake_up(&sz->driver->rbuf->wait_poll);
+
+       spin_unlock_irqrestore(&sz->timer_lock, flags);
+}
+
+static void flush_delay_buffer(struct usb_streamzap *sz)
+{
+       int data;
+       int empty = 1;
+
+       while (!lirc_buffer_empty(sz->delay_buf)) {
+               empty = 0;
+               lirc_buffer_read(sz->delay_buf, (unsigned char *) &data);
+               if (!lirc_buffer_full(sz->driver->rbuf)) {
+                       lirc_buffer_write(sz->driver->rbuf,
+                                           (unsigned char *) &data);
+               } else {
+                       dprintk("buffer overflow", sz->driver->minor);
+               }
+       }
+       if (!empty)
+               wake_up(&sz->driver->rbuf->wait_poll);
+}
+
+static void push(struct usb_streamzap *sz, unsigned char *data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sz->timer_lock, flags);
+       if (lirc_buffer_full(sz->delay_buf)) {
+               int read_data;
+
+               lirc_buffer_read(sz->delay_buf,
+                                  (unsigned char *) &read_data);
+               if (!lirc_buffer_full(sz->driver->rbuf)) {
+                       lirc_buffer_write(sz->driver->rbuf,
+                                           (unsigned char *) &read_data);
+               } else {
+                       dprintk("buffer overflow", sz->driver->minor);
+               }
+       }
+
+       lirc_buffer_write(sz->delay_buf, data);
+
+       if (!sz->timer_running) {
+               sz->delay_timer.expires = jiffies + HZ/10;
+               add_timer(&sz->delay_timer);
+               sz->timer_running = 1;
+       }
+
+       spin_unlock_irqrestore(&sz->timer_lock, flags);
+}
+
+static void push_full_pulse(struct usb_streamzap *sz,
+                           unsigned char value)
+{
+       int pulse;
+
+       if (sz->idle) {
+               long deltv;
+               int tmp;
+
+               sz->signal_last = sz->signal_start;
+               do_gettimeofday(&sz->signal_start);
+
+               deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec;
+               if (deltv > 15) {
+                       /* really long time */
+                       tmp = LIRC_SPACE(LIRC_VALUE_MASK);
+               } else {
+                       tmp = (int) (deltv*1000000+
+                                       sz->signal_start.tv_usec -
+                                       sz->signal_last.tv_usec);
+                       tmp -= sz->sum;
+                       tmp = LIRC_SPACE(tmp);
+               }
+               dprintk("ls %u", sz->driver->minor, tmp);
+               push(sz, (char *)&tmp);
+
+               sz->idle = 0;
+               sz->sum = 0;
+       }
+
+       pulse = ((int) value) * STREAMZAP_RESOLUTION;
+       pulse += STREAMZAP_RESOLUTION / 2;
+       sz->sum += pulse;
+       pulse = LIRC_PULSE(pulse);
+
+       dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK);
+       push(sz, (char *)&pulse);
+}
+
+static void push_half_pulse(struct usb_streamzap *sz,
+                           unsigned char value)
+{
+       push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4);
+}
+
+static void push_full_space(struct usb_streamzap *sz,
+                           unsigned char value)
+{
+       int space;
+
+       space = ((int) value)*STREAMZAP_RESOLUTION;
+       space += STREAMZAP_RESOLUTION/2;
+       sz->sum += space;
+       space = LIRC_SPACE(space);
+       dprintk("s %u", sz->driver->minor, space);
+       push(sz, (char *)&space);
+}
+
+static void push_half_space(struct usb_streamzap *sz,
+                           unsigned char value)
+{
+       push_full_space(sz, value & STREAMZAP_SPACE_MASK);
+}
+
+/**
+ * usb_streamzap_irq - IRQ handler
+ *
+ * This procedure is invoked on reception of data from
+ * the usb remote.
+ */
+static void usb_streamzap_irq(struct urb *urb)
+{
+       struct usb_streamzap *sz;
+       int             len;
+       unsigned int    i = 0;
+
+       if (!urb)
+               return;
+
+       sz = urb->context;
+       len = urb->actual_length;
+
+       switch (urb->status) {
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /*
+                * this urb is terminated, clean up.
+                * sz might already be invalid at this point
+                */
+               dprintk("urb status: %d", -1, urb->status);
+               return;
+       default:
+               break;
+       }
+
+       dprintk("received %d", sz->driver->minor, urb->actual_length);
+       if (!sz->flush) {
+               for (i = 0; i < urb->actual_length; i++) {
+                       dprintk("%d: %x", sz->driver->minor,
+                               i, (unsigned char) sz->buf_in[i]);
+                       switch (sz->decoder_state) {
+                       case PulseSpace:
+                               if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) ==
+                                   STREAMZAP_PULSE_MASK) {
+                                       sz->decoder_state = FullPulse;
+                                       continue;
+                               } else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK)
+                                          == STREAMZAP_SPACE_MASK) {
+                                       push_half_pulse(sz, sz->buf_in[i]);
+                                       sz->decoder_state = FullSpace;
+                                       continue;
+                               } else {
+                                       push_half_pulse(sz, sz->buf_in[i]);
+                                       push_half_space(sz, sz->buf_in[i]);
+                               }
+                               break;
+                       case FullPulse:
+                               push_full_pulse(sz, sz->buf_in[i]);
+                               sz->decoder_state = IgnorePulse;
+                               break;
+                       case FullSpace:
+                               if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
+                                       sz->idle = 1;
+                                       stop_timer(sz);
+                                       if (sz->timeout_enabled) {
+                                               int timeout =
+                                                       LIRC_TIMEOUT
+                                                       (STREAMZAP_TIMEOUT *
+                                                       STREAMZAP_RESOLUTION);
+                                               push(sz, (char *)&timeout);
+                                       }
+                                       flush_delay_buffer(sz);
+                               } else
+                                       push_full_space(sz, sz->buf_in[i]);
+                               sz->decoder_state = PulseSpace;
+                               break;
+                       case IgnorePulse:
+                               if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) ==
+                                   STREAMZAP_SPACE_MASK) {
+                                       sz->decoder_state = FullSpace;
+                                       continue;
+                               }
+                               push_half_space(sz, sz->buf_in[i]);
+                               sz->decoder_state = PulseSpace;
+                               break;
+                       }
+               }
+       }
+
+       usb_submit_urb(urb, GFP_ATOMIC);
+
+       return;
+}
+
+static const struct file_operations streamzap_fops = {
+       .owner          = THIS_MODULE,
+       .unlocked_ioctl = streamzap_ioctl,
+       .read           = lirc_dev_fop_read,
+       .write          = lirc_dev_fop_write,
+       .poll           = lirc_dev_fop_poll,
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+};
+
+
+/**
+ *     streamzap_probe
+ *
+ *     Called by usb-core to associated with a candidate device
+ *     On any failure the return value is the ERROR
+ *     On success return 0
+ */
+static int streamzap_probe(struct usb_interface *interface,
+                          const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct usb_host_interface *iface_host;
+       struct usb_streamzap *sz;
+       struct lirc_driver *driver;
+       struct lirc_buffer *lirc_buf;
+       struct lirc_buffer *delay_buf;
+       char buf[63], name[128] = "";
+       int retval = -ENOMEM;
+       int minor = 0;
+
+       /* Allocate space for device driver specific data */
+       sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL);
+       if (sz == NULL)
+               return -ENOMEM;
+
+       sz->udev = udev;
+       sz->interface = interface;
+
+       /* Check to ensure endpoint information matches requirements */
+       iface_host = interface->cur_altsetting;
+
+       if (iface_host->desc.bNumEndpoints != 1) {
+               err("%s: Unexpected desc.bNumEndpoints (%d)", __func__,
+                   iface_host->desc.bNumEndpoints);
+               retval = -ENODEV;
+               goto free_sz;
+       }
+
+       sz->endpoint = &(iface_host->endpoint[0].desc);
+       if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+           != USB_DIR_IN) {
+               err("%s: endpoint doesn't match input device 02%02x",
+                   __func__, sz->endpoint->bEndpointAddress);
+               retval = -ENODEV;
+               goto free_sz;
+       }
+
+       if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+           != USB_ENDPOINT_XFER_INT) {
+               err("%s: endpoint attributes don't match xfer 02%02x",
+                   __func__, sz->endpoint->bmAttributes);
+               retval = -ENODEV;
+               goto free_sz;
+       }
+
+       if (sz->endpoint->wMaxPacketSize == 0) {
+               err("%s: endpoint message size==0? ", __func__);
+               retval = -ENODEV;
+               goto free_sz;
+       }
+
+       /* Allocate the USB buffer and IRQ URB */
+
+       sz->buf_in_len = sz->endpoint->wMaxPacketSize;
+       sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len,
+                                     GFP_ATOMIC, &sz->dma_in);
+       if (sz->buf_in == NULL)
+               goto free_sz;
+
+       sz->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+       if (sz->urb_in == NULL)
+               goto free_sz;
+
+       /* Connect this device to the LIRC sub-system */
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver)
+               goto free_sz;
+
+       lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!lirc_buf)
+               goto free_driver;
+       if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN))
+               goto kfree_lirc_buf;
+
+       delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!delay_buf)
+               goto free_lirc_buf;
+       if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN))
+               goto kfree_delay_buf;
+
+       sz->driver = driver;
+       strcpy(sz->driver->name, DRIVER_NAME);
+       sz->driver->minor = -1;
+       sz->driver->sample_rate = 0;
+       sz->driver->code_length = sizeof(int) * 8;
+       sz->driver->features = LIRC_CAN_REC_MODE2 |
+               LIRC_CAN_GET_REC_RESOLUTION |
+               LIRC_CAN_SET_REC_TIMEOUT;
+       sz->driver->data = sz;
+       sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION;
+       sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION;
+       sz->driver->rbuf = lirc_buf;
+       sz->delay_buf = delay_buf;
+       sz->driver->set_use_inc = &streamzap_use_inc;
+       sz->driver->set_use_dec = &streamzap_use_dec;
+       sz->driver->fops = &streamzap_fops;
+       sz->driver->dev = &interface->dev;
+       sz->driver->owner = THIS_MODULE;
+
+       sz->idle = 1;
+       sz->decoder_state = PulseSpace;
+       init_timer(&sz->delay_timer);
+       sz->delay_timer.function = delay_timeout;
+       sz->delay_timer.data = (unsigned long) sz;
+       sz->timer_running = 0;
+       spin_lock_init(&sz->timer_lock);
+
+       init_timer(&sz->flush_timer);
+       sz->flush_timer.function = flush_timeout;
+       sz->flush_timer.data = (unsigned long) sz;
+       /* Complete final initialisations */
+
+       usb_fill_int_urb(sz->urb_in, udev,
+               usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress),
+               sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz,
+               sz->endpoint->bInterval);
+       sz->urb_in->transfer_dma = sz->dma_in;
+       sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       if (udev->descriptor.iManufacturer
+           && usb_string(udev, udev->descriptor.iManufacturer,
+                         buf, sizeof(buf)) > 0)
+               strlcpy(name, buf, sizeof(name));
+
+       if (udev->descriptor.iProduct
+           && usb_string(udev, udev->descriptor.iProduct,
+                         buf, sizeof(buf)) > 0)
+               snprintf(name + strlen(name), sizeof(name) - strlen(name),
+                        " %s", buf);
+
+       minor = lirc_register_driver(driver);
+
+       if (minor < 0)
+               goto free_delay_buf;
+
+       sz->driver->minor = minor;
+
+       usb_set_intfdata(interface, sz);
+
+       printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n",
+              sz->driver->minor, name,
+              udev->bus->busnum, sz->udev->devnum);
+
+       return 0;
+
+free_delay_buf:
+       lirc_buffer_free(sz->delay_buf);
+kfree_delay_buf:
+       kfree(delay_buf);
+free_lirc_buf:
+       lirc_buffer_free(sz->driver->rbuf);
+kfree_lirc_buf:
+       kfree(lirc_buf);
+free_driver:
+       kfree(driver);
+free_sz:
+       if (retval == -ENOMEM)
+               err("Out of memory");
+
+       if (sz) {
+               usb_free_urb(sz->urb_in);
+               usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+               kfree(sz);
+       }
+
+       return retval;
+}
+
+static int streamzap_use_inc(void *data)
+{
+       struct usb_streamzap *sz = data;
+
+       if (!sz) {
+               dprintk("%s called with no context", -1, __func__);
+               return -EINVAL;
+       }
+       dprintk("set use inc", sz->driver->minor);
+
+       lirc_buffer_clear(sz->driver->rbuf);
+       lirc_buffer_clear(sz->delay_buf);
+
+       sz->flush_timer.expires = jiffies + HZ;
+       sz->flush = 1;
+       add_timer(&sz->flush_timer);
+
+       sz->urb_in->dev = sz->udev;
+       if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+               dprintk("open result = -EIO error submitting urb",
+                       sz->driver->minor);
+               return -EIO;
+       }
+       sz->in_use++;
+
+       return 0;
+}
+
+static void streamzap_use_dec(void *data)
+{
+       struct usb_streamzap *sz = data;
+
+       if (!sz) {
+               dprintk("%s called with no context", -1, __func__);
+               return;
+       }
+       dprintk("set use dec", sz->driver->minor);
+
+       if (sz->flush) {
+               sz->flush = 0;
+               del_timer_sync(&sz->flush_timer);
+       }
+
+       usb_kill_urb(sz->urb_in);
+
+       stop_timer(sz);
+
+       sz->in_use--;
+}
+
+static long streamzap_ioctl(struct file *filep, unsigned int cmd,
+                           unsigned long arg)
+{
+       int result = 0;
+       int val;
+       struct usb_streamzap *sz = lirc_get_pdata(filep);
+
+       switch (cmd) {
+       case LIRC_GET_REC_RESOLUTION:
+               result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg);
+               break;
+       case LIRC_SET_REC_TIMEOUT:
+               result = get_user(val, (int *)arg);
+               if (result == 0) {
+                       if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION)
+                               sz->timeout_enabled = 1;
+                       else if (val == 0)
+                               sz->timeout_enabled = 0;
+                       else
+                               result = -EINVAL;
+               }
+               break;
+       default:
+               return lirc_dev_fop_ioctl(filep, cmd, arg);
+       }
+       return result;
+}
+
+/**
+ * streamzap_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ *
+ * This routine guarantees that the driver will not submit any more urbs
+ * by clearing dev->udev.  It is also supposed to terminate any currently
+ * active urbs.  Unfortunately, usb_bulk_msg(), used in streamzap_read(),
+ * does not provide any way to do this.
+ */
+static void streamzap_disconnect(struct usb_interface *interface)
+{
+       struct usb_streamzap *sz;
+       int errnum;
+       int minor;
+
+       sz = usb_get_intfdata(interface);
+
+       /* unregister from the LIRC sub-system */
+
+       errnum = lirc_unregister_driver(sz->driver->minor);
+       if (errnum != 0)
+               dprintk("error in lirc_unregister: (returned %d)",
+                       sz->driver->minor, errnum);
+
+       lirc_buffer_free(sz->delay_buf);
+       lirc_buffer_free(sz->driver->rbuf);
+
+       /* unregister from the USB sub-system */
+
+       usb_free_urb(sz->urb_in);
+
+       usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+
+       minor = sz->driver->minor;
+       kfree(sz->driver->rbuf);
+       kfree(sz->driver);
+       kfree(sz->delay_buf);
+       kfree(sz);
+
+       printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor);
+}
+
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct usb_streamzap *sz = usb_get_intfdata(intf);
+
+       printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor);
+       if (sz->in_use) {
+               if (sz->flush) {
+                       sz->flush = 0;
+                       del_timer_sync(&sz->flush_timer);
+               }
+
+               stop_timer(sz);
+
+               usb_kill_urb(sz->urb_in);
+       }
+       return 0;
+}
+
+static int streamzap_resume(struct usb_interface *intf)
+{
+       struct usb_streamzap *sz = usb_get_intfdata(intf);
+
+       lirc_buffer_clear(sz->driver->rbuf);
+       lirc_buffer_clear(sz->delay_buf);
+
+       if (sz->in_use) {
+               sz->flush_timer.expires = jiffies + HZ;
+               sz->flush = 1;
+               add_timer(&sz->flush_timer);
+
+               sz->urb_in->dev = sz->udev;
+               if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+                       dprintk("open result = -EIO error submitting urb",
+                               sz->driver->minor);
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+/**
+ *     usb_streamzap_init
+ */
+static int __init usb_streamzap_init(void)
+{
+       int result;
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&streamzap_driver);
+
+       if (result) {
+               err("usb_register failed. Error number %d",
+                   result);
+               return result;
+       }
+
+       printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n");
+       return 0;
+}
+
+/**
+ *     usb_streamzap_exit
+ */
+static void __exit usb_streamzap_exit(void)
+{
+       usb_deregister(&streamzap_driver);
+}
+
+
+module_init(usb_streamzap_init);
+module_exit(usb_streamzap_exit);
+
+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c
new file mode 100644 (file)
index 0000000..e345ab9
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * lirc_ttusbir.c
+ *
+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
+ *
+ * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
+ *
+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver.
+ * The receiver delivers the IR signal as raw sampled true/false data in
+ * isochronous USB packets each of size 128 byte.
+ * Currently the driver reduces the sampling rate by factor of 8 as this
+ * is still more than enough to decode RC-5 - others should be analyzed.
+ * But the driver does not rely on RC-5 it should be able to decode every
+ * IR signal that is not too fast.
+ */
+
+/*
+ *  This program is free software; 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/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
+MODULE_LICENSE("GPL");
+
+/* #define DEBUG */
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+#define DPRINTK(_x_, a...)
+#endif
+
+/* function declarations */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void disconnect(struct usb_interface *intf);
+static void urb_complete(struct urb *urb);
+static int set_use_inc(void *data);
+static void set_use_dec(void *data);
+
+static int num_urbs = 2;
+module_param(num_urbs, int, S_IRUGO);
+MODULE_PARM_DESC(num_urbs,
+                "Number of URBs in queue. Try to increase to 4 in case "
+                "of problems (default: 2; minimum: 2)");
+
+/* table of devices that work with this driver */
+static struct usb_device_id device_id_table[] = {
+       /* TechnoTrend USB IR Receiver */
+       { USB_DEVICE(0x0B48, 0x2003) },
+       /* Terminating entry */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, device_id_table);
+
+/* USB driver definition */
+static struct usb_driver usb_driver = {
+       .name = "TTUSBIR",
+       .id_table = &(device_id_table[0]),
+       .probe = probe,
+       .disconnect = disconnect,
+};
+
+/* USB device definition */
+struct ttusbir_device {
+       struct usb_driver *usb_driver;
+       struct usb_device *udev;
+       struct usb_interface *interf;
+       struct usb_class_driver class_driver;
+       unsigned int ifnum; /* Interface number to use */
+       unsigned int alt_setting; /* alternate setting to use */
+       unsigned int endpoint; /* Endpoint to use */
+       struct urb **urb; /* num_urb URB pointers*/
+       char **buffer; /* 128 byte buffer for each URB */
+       struct lirc_buffer rbuf; /* Buffer towards LIRC */
+       struct lirc_driver driver;
+       int minor;
+       int last_pulse; /* remembers if last received byte was pulse or space */
+       int last_num; /* remembers how many last bytes appeared */
+       int opened;
+};
+
+/*** LIRC specific functions ***/
+static int set_use_inc(void *data)
+{
+       int i, retval;
+       struct ttusbir_device *ttusbir = data;
+
+       DPRINTK("Sending first URBs\n");
+       /* @TODO Do I need to check if I am already opened */
+       ttusbir->opened = 1;
+
+       for (i = 0; i < num_urbs; i++) {
+               retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
+               if (retval) {
+                       err("%s: usb_submit_urb failed on urb %d",
+                           __func__, i);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       struct ttusbir_device *ttusbir = data;
+
+       DPRINTK("Device closed\n");
+
+       ttusbir->opened = 0;
+}
+
+/*** USB specific functions ***/
+
+/*
+ * This mapping table is used to do a very simple filtering of the
+ * input signal.
+ * For a value with at least 4 bits set it returns 0xFF otherwise
+ * 0x00.  For faster IR signals this can not be used. But for RC-5 we
+ * still have about 14 samples per pulse/space, i.e. we sample with 14
+ * times higher frequency than the signal frequency
+ */
+const unsigned char map_table[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static void urb_complete(struct urb *urb)
+{
+       struct ttusbir_device *ttusbir;
+       unsigned char *buf;
+       int i;
+       int l;
+
+       ttusbir = urb->context;
+
+       if (!ttusbir->opened)
+               return;
+
+       buf = (unsigned char *)urb->transfer_buffer;
+
+       for (i = 0; i < 128; i++) {
+               /* Here we do the filtering and some kind of down sampling */
+               buf[i] = ~map_table[buf[i]];
+               if (ttusbir->last_pulse == buf[i]) {
+                       if (ttusbir->last_num < PULSE_MASK/63)
+                               ttusbir->last_num++;
+               /*
+                * else we are in a idle period and do not need to
+                * increment any longer
+                */
+               } else {
+                       l = ttusbir->last_num * 62; /* about 62 = us/byte */
+                       if (ttusbir->last_pulse) /* pulse or space? */
+                               l |= PULSE_BIT;
+                       if (!lirc_buffer_full(&ttusbir->rbuf)) {
+                               lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
+                               wake_up_interruptible(&ttusbir->rbuf.wait_poll);
+                       }
+                       ttusbir->last_num = 0;
+                       ttusbir->last_pulse = buf[i];
+               }
+       }
+       usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
+}
+
+/*
+ * Called whenever the USB subsystem thinks we could be the right driver
+ * to handle this device
+ */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       int alt_set, endp;
+       int found = 0;
+       int i, j;
+       int struct_size;
+       struct usb_host_interface *host_interf;
+       struct usb_interface_descriptor *interf_desc;
+       struct usb_host_endpoint *host_endpoint;
+       struct ttusbir_device *ttusbir;
+
+       DPRINTK("Module ttusbir probe\n");
+
+       /* To reduce memory fragmentation we use only one allocation */
+       struct_size =  sizeof(struct ttusbir_device) +
+               (sizeof(struct urb *) * num_urbs) +
+               (sizeof(char *) * num_urbs) +
+               (num_urbs * 128);
+       ttusbir = kzalloc(struct_size, GFP_KERNEL);
+       if (!ttusbir)
+               return -ENOMEM;
+
+       ttusbir->urb = (struct urb **)((char *)ttusbir +
+                                     sizeof(struct ttusbir_device));
+       ttusbir->buffer = (char **)((char *)ttusbir->urb +
+                                  (sizeof(struct urb *) * num_urbs));
+       for (i = 0; i < num_urbs; i++)
+               ttusbir->buffer[i] = (char *)ttusbir->buffer +
+                       (sizeof(char *)*num_urbs) + (i * 128);
+
+       ttusbir->usb_driver = &usb_driver;
+       ttusbir->alt_setting = -1;
+       /* @TODO check if error can be returned */
+       ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
+       ttusbir->interf = intf;
+       ttusbir->last_pulse = 0x00;
+       ttusbir->last_num = 0;
+
+       /*
+        * Now look for interface setting we can handle
+        * We are searching for the alt setting where end point
+        * 0x82 has max packet size 16
+        */
+       for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
+               host_interf = &intf->altsetting[alt_set];
+               interf_desc = &host_interf->desc;
+               for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
+                       host_endpoint = &host_interf->endpoint[endp];
+                       if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
+                           (host_endpoint->desc.wMaxPacketSize == 0x10)) {
+                               ttusbir->alt_setting = alt_set;
+                               ttusbir->endpoint = endp;
+                               found = 1;
+                               break;
+                       }
+               }
+       }
+       if (ttusbir->alt_setting != -1)
+               DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
+       else {
+               err("Could not find alternate setting\n");
+               kfree(ttusbir);
+               return -EINVAL;
+       }
+
+       /* OK lets setup this interface setting */
+       usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
+
+       /* Store device info in interface structure */
+       usb_set_intfdata(intf, ttusbir);
+
+       /* Register as a LIRC driver */
+       if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
+               err("Could not get memory for LIRC data buffer\n");
+               usb_set_intfdata(intf, NULL);
+               kfree(ttusbir);
+               return -ENOMEM;
+       }
+       strcpy(ttusbir->driver.name, "TTUSBIR");
+       ttusbir->driver.minor = -1;
+       ttusbir->driver.code_length = 1;
+       ttusbir->driver.sample_rate = 0;
+       ttusbir->driver.data = ttusbir;
+       ttusbir->driver.add_to_buf = NULL;
+       ttusbir->driver.rbuf = &ttusbir->rbuf;
+       ttusbir->driver.set_use_inc = set_use_inc;
+       ttusbir->driver.set_use_dec = set_use_dec;
+       ttusbir->driver.dev = &intf->dev;
+       ttusbir->driver.owner = THIS_MODULE;
+       ttusbir->driver.features = LIRC_CAN_REC_MODE2;
+       ttusbir->minor = lirc_register_driver(&ttusbir->driver);
+       if (ttusbir->minor < 0) {
+               err("Error registering as LIRC driver\n");
+               usb_set_intfdata(intf, NULL);
+               lirc_buffer_free(&ttusbir->rbuf);
+               kfree(ttusbir);
+               return -EIO;
+       }
+
+       /* Allocate and setup the URB that we will use to talk to the device */
+       for (i = 0; i < num_urbs; i++) {
+               ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
+               if (!ttusbir->urb[i]) {
+                       err("Could not allocate memory for the URB\n");
+                       for (j = i - 1; j >= 0; j--)
+                               kfree(ttusbir->urb[j]);
+                       lirc_buffer_free(&ttusbir->rbuf);
+                       lirc_unregister_driver(ttusbir->minor);
+                       kfree(ttusbir);
+                       usb_set_intfdata(intf, NULL);
+                       return -ENOMEM;
+               }
+               ttusbir->urb[i]->dev = ttusbir->udev;
+               ttusbir->urb[i]->context = ttusbir;
+               ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
+                                                       ttusbir->endpoint);
+               ttusbir->urb[i]->interval = 1;
+               ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
+               ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
+               ttusbir->urb[i]->complete = urb_complete;
+               ttusbir->urb[i]->number_of_packets = 8;
+               ttusbir->urb[i]->transfer_buffer_length = 128;
+               for (j = 0; j < 8; j++) {
+                       ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
+                       ttusbir->urb[i]->iso_frame_desc[j].length = 16;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Called when the driver is unloaded or the device is unplugged
+ */
+static void disconnect(struct usb_interface *intf)
+{
+       int i;
+       struct ttusbir_device *ttusbir;
+
+       DPRINTK("Module ttusbir disconnect\n");
+
+       ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
+       lirc_unregister_driver(ttusbir->minor);
+       DPRINTK("unregistered\n");
+
+       for (i = 0; i < num_urbs; i++) {
+               usb_kill_urb(ttusbir->urb[i]);
+               usb_free_urb(ttusbir->urb[i]);
+       }
+       DPRINTK("URBs killed\n");
+       lirc_buffer_free(&ttusbir->rbuf);
+       kfree(ttusbir);
+}
+
+static int ttusbir_init_module(void)
+{
+       int result;
+
+       DPRINTK(KERN_DEBUG "Module ttusbir init\n");
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&usb_driver);
+       if (result)
+               err("usb_register failed. Error number %d", result);
+       return result;
+}
+
+static void ttusbir_exit_module(void)
+{
+       printk(KERN_DEBUG "Module ttusbir exit\n");
+       usb_deregister(&usb_driver);
+}
+
+module_init(ttusbir_init_module);
+module_exit(ttusbir_exit_module);
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
new file mode 100644 (file)
index 0000000..100caab
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ * i2c IR lirc driver for devices with zilog IR processors
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ *      Michal Kochanowicz <mkochano@pld.org.pl>
+ *      Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ *      Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ *      Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ *      Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge PVR-150 IR TX device by
+ *      Mark Weaver <mark@npsl.co.uk>
+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150
+ *     Jarod Wilson <jarod@redhat.com>
+ *
+ * parts are cut&pasted from the lirc_i2c.c 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+
+#include <media/lirc_dev.h>
+#include <media/lirc.h>
+
+struct IR {
+       struct lirc_driver l;
+
+       /* Device info */
+       struct mutex ir_lock;
+       int open;
+
+       /* RX device */
+       struct i2c_client c_rx;
+       int have_rx;
+
+       /* RX device buffer & lock */
+       struct lirc_buffer buf;
+       struct mutex buf_lock;
+
+       /* RX polling thread data */
+       struct completion *t_notify;
+       struct completion *t_notify2;
+       int shutdown;
+       struct task_struct *task;
+
+       /* RX read data */
+       unsigned char b[3];
+
+       /* TX device */
+       struct i2c_client c_tx;
+       int need_boot;
+       int have_tx;
+};
+
+/* Minor -> data mapping */
+static struct IR *ir_devices[MAX_IRCTL_DEVICES];
+
+/* Block size for IR transmitter */
+#define TX_BLOCK_SIZE  99
+
+/* Hauppauge IR transmitter data */
+struct tx_data_struct {
+       /* Boot block */
+       unsigned char *boot_data;
+
+       /* Start of binary data block */
+       unsigned char *datap;
+
+       /* End of binary data block */
+       unsigned char *endp;
+
+       /* Number of installed codesets */
+       unsigned int num_code_sets;
+
+       /* Pointers to codesets */
+       unsigned char **code_sets;
+
+       /* Global fixed data template */
+       int fixed[TX_BLOCK_SIZE];
+};
+
+static struct tx_data_struct *tx_data;
+static struct mutex tx_data_lock;
+
+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
+                                       ## args)
+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+
+#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX"
+#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX"
+
+/* module parameters */
+static int debug;      /* debug output */
+static int disable_rx; /* disable RX device */
+static int disable_tx; /* disable TX device */
+static int minor = -1; /* minor number */
+
+#define dprintk(fmt, args...)                                          \
+       do {                                                            \
+               if (debug)                                              \
+                       printk(KERN_DEBUG KBUILD_MODNAME ": " fmt,      \
+                                ## args);                              \
+       } while (0)
+
+static int add_to_buf(struct IR *ir)
+{
+       __u16 code;
+       unsigned char codes[2];
+       unsigned char keybuf[6];
+       int got_data = 0;
+       int ret;
+       int failures = 0;
+       unsigned char sendbuf[1] = { 0 };
+
+       if (lirc_buffer_full(&ir->buf)) {
+               dprintk("buffer overflow\n");
+               return -EOVERFLOW;
+       }
+
+       /*
+        * service the device as long as it is returning
+        * data and we have space
+        */
+       do {
+               /*
+                * Lock i2c bus for the duration.  RX/TX chips interfere so
+                * this is worth it
+                */
+               mutex_lock(&ir->ir_lock);
+
+               /*
+                * Send random "poll command" (?)  Windows driver does this
+                * and it is a good point to detect chip failure.
+                */
+               ret = i2c_master_send(&ir->c_rx, sendbuf, 1);
+               if (ret != 1) {
+                       zilog_error("i2c_master_send failed with %d\n", ret);
+                       if (failures >= 3) {
+                               mutex_unlock(&ir->ir_lock);
+                               zilog_error("unable to read from the IR chip "
+                                           "after 3 resets, giving up\n");
+                               return ret;
+                       }
+
+                       /* Looks like the chip crashed, reset it */
+                       zilog_error("polling the IR receiver chip failed, "
+                                   "trying reset\n");
+
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout((100 * HZ + 999) / 1000);
+                       ir->need_boot = 1;
+
+                       ++failures;
+                       mutex_unlock(&ir->ir_lock);
+                       continue;
+               }
+
+               ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf));
+               mutex_unlock(&ir->ir_lock);
+               if (ret != sizeof(keybuf)) {
+                       zilog_error("i2c_master_recv failed with %d -- "
+                                   "keeping last read buffer\n", ret);
+               } else {
+                       ir->b[0] = keybuf[3];
+                       ir->b[1] = keybuf[4];
+                       ir->b[2] = keybuf[5];
+                       dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+               }
+
+               /* key pressed ? */
+#ifdef I2C_HW_B_HDPVR
+               if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) {
+                       if (got_data && (keybuf[0] == 0x80))
+                               return 0;
+                       else if (got_data && (keybuf[0] == 0x00))
+                               return -ENODATA;
+               } else if ((ir->b[0] & 0x80) == 0)
+#else
+               if ((ir->b[0] & 0x80) == 0)
+#endif
+                       return got_data ? 0 : -ENODATA;
+
+               /* look what we have */
+               code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2);
+
+               codes[0] = (code >> 8) & 0xff;
+               codes[1] = code & 0xff;
+
+               /* return it */
+               lirc_buffer_write(&ir->buf, codes);
+               ++got_data;
+       } while (!lirc_buffer_full(&ir->buf));
+
+       return 0;
+}
+
+/*
+ * Main function of the polling thread -- from lirc_dev.
+ * We don't fit the LIRC model at all anymore.  This is horrible, but
+ * basically we have a single RX/TX device with a nasty failure mode
+ * that needs to be accounted for across the pair.  lirc lets us provide
+ * fops, but prevents us from using the internal polling, etc. if we do
+ * so.  Hence the replication.  Might be neater to extend the LIRC model
+ * to account for this but I'd think it's a very special case of seriously
+ * messed up hardware.
+ */
+static int lirc_thread(void *arg)
+{
+       struct IR *ir = arg;
+
+       if (ir->t_notify != NULL)
+               complete(ir->t_notify);
+
+       dprintk("poll thread started\n");
+
+       do {
+               if (ir->open) {
+                       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 it (bad!).  This is
+                        * therefore just sufficient to catch all of the
+                        * button presses.  It makes the remote much more
+                        * responsive.  You can see the difference by
+                        * running irw and holding down a button.  With
+                        * 100ms, the old polling interval, you'll notice
+                        * breaks in the repeat sequence corresponding to
+                        * lost keypresses.
+                        */
+                       schedule_timeout((260 * HZ) / 1000);
+                       if (ir->shutdown)
+                               break;
+                       if (!add_to_buf(ir))
+                               wake_up_interruptible(&ir->buf.wait_poll);
+               } else {
+                       /* if device not opened so we can sleep half a second */
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ/2);
+               }
+       } while (!ir->shutdown);
+
+       if (ir->t_notify2 != NULL)
+               wait_for_completion(ir->t_notify2);
+
+       ir->task = NULL;
+       if (ir->t_notify != NULL)
+               complete(ir->t_notify);
+
+       dprintk("poll thread ended\n");
+       return 0;
+}
+
+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->c_rx.addr)
+               i2c_use_client(&ir->c_rx);
+       if (ir->c_tx.addr)
+               i2c_use_client(&ir->c_tx);
+
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       struct IR *ir = data;
+
+       if (ir->c_rx.addr)
+               i2c_release_client(&ir->c_rx);
+       if (ir->c_tx.addr)
+               i2c_release_client(&ir->c_tx);
+       if (ir->l.owner != NULL)
+               module_put(ir->l.owner);
+}
+
+/* safe read of a uint32 (always network byte order) */
+static int read_uint32(unsigned char **data,
+                                    unsigned char *endp, unsigned int *val)
+{
+       if (*data + 4 > endp)
+               return 0;
+       *val = ((*data)[0] << 24) | ((*data)[1] << 16) |
+              ((*data)[2] << 8) | (*data)[3];
+       *data += 4;
+       return 1;
+}
+
+/* safe read of a uint8 */
+static int read_uint8(unsigned char **data,
+                                   unsigned char *endp, unsigned char *val)
+{
+       if (*data + 1 > endp)
+               return 0;
+       *val = *((*data)++);
+       return 1;
+}
+
+/* safe skipping of N bytes */
+static int skip(unsigned char **data,
+                             unsigned char *endp, unsigned int distance)
+{
+       if (*data + distance > endp)
+               return 0;
+       *data += distance;
+       return 1;
+}
+
+/* decompress key data into the given buffer */
+static int get_key_data(unsigned char *buf,
+                            unsigned int codeset, unsigned int key)
+{
+       unsigned char *data, *endp, *diffs, *key_block;
+       unsigned char keys, ndiffs, id;
+       unsigned int base, lim, pos, i;
+
+       /* Binary search for the codeset */
+       for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) {
+               pos = base + (lim >> 1);
+               data = tx_data->code_sets[pos];
+
+               if (!read_uint32(&data, tx_data->endp, &i))
+                       goto corrupt;
+
+               if (i == codeset)
+                       break;
+               else if (codeset > i) {
+                       base = pos + 1;
+                       --lim;
+               }
+       }
+       /* Not found? */
+       if (!lim)
+               return -EPROTO;
+
+       /* Set end of data block */
+       endp = pos < tx_data->num_code_sets - 1 ?
+               tx_data->code_sets[pos + 1] : tx_data->endp;
+
+       /* Read the block header */
+       if (!read_uint8(&data, endp, &keys) ||
+           !read_uint8(&data, endp, &ndiffs) ||
+           ndiffs > TX_BLOCK_SIZE || keys == 0)
+               goto corrupt;
+
+       /* Save diffs & skip */
+       diffs = data;
+       if (!skip(&data, endp, ndiffs))
+               goto corrupt;
+
+       /* Read the id of the first key */
+       if (!read_uint8(&data, endp, &id))
+               goto corrupt;
+
+       /* Unpack the first key's data */
+       for (i = 0; i < TX_BLOCK_SIZE; ++i) {
+               if (tx_data->fixed[i] == -1) {
+                       if (!read_uint8(&data, endp, &buf[i]))
+                               goto corrupt;
+               } else {
+                       buf[i] = (unsigned char)tx_data->fixed[i];
+               }
+       }
+
+       /* Early out key found/not found */
+       if (key == id)
+               return 0;
+       if (keys == 1)
+               return -EPROTO;
+
+       /* Sanity check */
+       key_block = data;
+       if (!skip(&data, endp, (keys - 1) * (ndiffs + 1)))
+               goto corrupt;
+
+       /* Binary search for the key */
+       for (base = 0, lim = keys - 1; lim; lim >>= 1) {
+               /* Seek to block */
+               unsigned char *key_data;
+               pos = base + (lim >> 1);
+               key_data = key_block + (ndiffs + 1) * pos;
+
+               if (*key_data == key) {
+                       /* skip key id */
+                       ++key_data;
+
+                       /* found, so unpack the diffs */
+                       for (i = 0; i < ndiffs; ++i) {
+                               unsigned char val;
+                               if (!read_uint8(&key_data, endp, &val) ||
+                                   diffs[i] >= TX_BLOCK_SIZE)
+                                       goto corrupt;
+                               buf[diffs[i]] = val;
+                       }
+
+                       return 0;
+               } else if (key > *key_data) {
+                       base = pos + 1;
+                       --lim;
+               }
+       }
+       /* Key not found */
+       return -EPROTO;
+
+corrupt:
+       zilog_error("firmware is corrupt\n");
+       return -EFAULT;
+}
+
+/* send a block of data to the IR TX device */
+static int send_data_block(struct IR *ir, unsigned char *data_block)
+{
+       int i, j, ret;
+       unsigned char buf[5];
+
+       for (i = 0; i < TX_BLOCK_SIZE;) {
+               int tosend = TX_BLOCK_SIZE - i;
+               if (tosend > 4)
+                       tosend = 4;
+               buf[0] = (unsigned char)(i + 1);
+               for (j = 0; j < tosend; ++j)
+                       buf[1 + j] = data_block[i + j];
+               dprintk("%02x %02x %02x %02x %02x",
+                       buf[0], buf[1], buf[2], buf[3], buf[4]);
+               ret = i2c_master_send(&ir->c_tx, buf, tosend + 1);
+               if (ret != tosend + 1) {
+                       zilog_error("i2c_master_send failed with %d\n", ret);
+                       return ret < 0 ? ret : -EFAULT;
+               }
+               i += tosend;
+       }
+       return 0;
+}
+
+/* send boot data to the IR TX device */
+static int send_boot_data(struct IR *ir)
+{
+       int ret;
+       unsigned char buf[4];
+
+       /* send the boot block */
+       ret = send_data_block(ir, tx_data->boot_data);
+       if (ret != 0)
+               return ret;
+
+       /* kick it off? */
+       buf[0] = 0x00;
+       buf[1] = 0x20;
+       ret = i2c_master_send(&ir->c_tx, buf, 2);
+       if (ret != 2) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+       ret = i2c_master_send(&ir->c_tx, buf, 1);
+       if (ret != 1) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Here comes the firmware version... (hopefully) */
+       ret = i2c_master_recv(&ir->c_tx, buf, 4);
+       if (ret != 4) {
+               zilog_error("i2c_master_recv failed with %d\n", ret);
+               return 0;
+       }
+       if (buf[0] != 0x80) {
+               zilog_error("unexpected IR TX response: %02x\n", buf[0]);
+               return 0;
+       }
+       zilog_notify("Zilog/Hauppauge IR blaster firmware version "
+                    "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]);
+
+       return 0;
+}
+
+/* unload "firmware", lock held */
+static void fw_unload_locked(void)
+{
+       if (tx_data) {
+               if (tx_data->code_sets)
+                       vfree(tx_data->code_sets);
+
+               if (tx_data->datap)
+                       vfree(tx_data->datap);
+
+               vfree(tx_data);
+               tx_data = NULL;
+               dprintk("successfully unloaded IR blaster firmware\n");
+       }
+}
+
+/* unload "firmware" for the IR TX device */
+static void fw_unload(void)
+{
+       mutex_lock(&tx_data_lock);
+       fw_unload_locked();
+       mutex_unlock(&tx_data_lock);
+}
+
+/* load "firmware" for the IR TX device */
+static int fw_load(struct IR *ir)
+{
+       int ret;
+       unsigned int i;
+       unsigned char *data, version, num_global_fixed;
+       const struct firmware *fw_entry;
+
+       /* Already loaded? */
+       mutex_lock(&tx_data_lock);
+       if (tx_data) {
+               ret = 0;
+               goto out;
+       }
+
+       /* Request codeset data file */
+       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev);
+       if (ret != 0) {
+               zilog_error("firmware haup-ir-blaster.bin not available "
+                           "(%d)\n", ret);
+               ret = ret < 0 ? ret : -EFAULT;
+               goto out;
+       }
+       dprintk("firmware of size %zu loaded\n", fw_entry->size);
+
+       /* Parse the file */
+       tx_data = vmalloc(sizeof(*tx_data));
+       if (tx_data == NULL) {
+               zilog_error("out of memory\n");
+               release_firmware(fw_entry);
+               ret = -ENOMEM;
+               goto out;
+       }
+       tx_data->code_sets = NULL;
+
+       /* Copy the data so hotplug doesn't get confused and timeout */
+       tx_data->datap = vmalloc(fw_entry->size);
+       if (tx_data->datap == NULL) {
+               zilog_error("out of memory\n");
+               release_firmware(fw_entry);
+               vfree(tx_data);
+               ret = -ENOMEM;
+               goto out;
+       }
+       memcpy(tx_data->datap, fw_entry->data, fw_entry->size);
+       tx_data->endp = tx_data->datap + fw_entry->size;
+       release_firmware(fw_entry); fw_entry = NULL;
+
+       /* Check version */
+       data = tx_data->datap;
+       if (!read_uint8(&data, tx_data->endp, &version))
+               goto corrupt;
+       if (version != 1) {
+               zilog_error("unsupported code set file version (%u, expected"
+                           "1) -- please upgrade to a newer driver",
+                           version);
+               fw_unload_locked();
+               ret = -EFAULT;
+               goto out;
+       }
+
+       /* Save boot block for later */
+       tx_data->boot_data = data;
+       if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE))
+               goto corrupt;
+
+       if (!read_uint32(&data, tx_data->endp,
+                             &tx_data->num_code_sets))
+               goto corrupt;
+
+       dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets);
+
+       tx_data->code_sets = vmalloc(
+               tx_data->num_code_sets * sizeof(char *));
+       if (tx_data->code_sets == NULL) {
+               fw_unload_locked();
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < TX_BLOCK_SIZE; ++i)
+               tx_data->fixed[i] = -1;
+
+       /* Read global fixed data template */
+       if (!read_uint8(&data, tx_data->endp, &num_global_fixed) ||
+           num_global_fixed > TX_BLOCK_SIZE)
+               goto corrupt;
+       for (i = 0; i < num_global_fixed; ++i) {
+               unsigned char pos, val;
+               if (!read_uint8(&data, tx_data->endp, &pos) ||
+                   !read_uint8(&data, tx_data->endp, &val) ||
+                   pos >= TX_BLOCK_SIZE)
+                       goto corrupt;
+               tx_data->fixed[pos] = (int)val;
+       }
+
+       /* Filch out the position of each code set */
+       for (i = 0; i < tx_data->num_code_sets; ++i) {
+               unsigned int id;
+               unsigned char keys;
+               unsigned char ndiffs;
+
+               /* Save the codeset position */
+               tx_data->code_sets[i] = data;
+
+               /* Read header */
+               if (!read_uint32(&data, tx_data->endp, &id) ||
+                   !read_uint8(&data, tx_data->endp, &keys) ||
+                   !read_uint8(&data, tx_data->endp, &ndiffs) ||
+                   ndiffs > TX_BLOCK_SIZE || keys == 0)
+                       goto corrupt;
+
+               /* skip diff positions */
+               if (!skip(&data, tx_data->endp, ndiffs))
+                       goto corrupt;
+
+               /*
+                * After the diffs we have the first key id + data -
+                * global fixed
+                */
+               if (!skip(&data, tx_data->endp,
+                              1 + TX_BLOCK_SIZE - num_global_fixed))
+                       goto corrupt;
+
+               /* Then we have keys-1 blocks of key id+diffs */
+               if (!skip(&data, tx_data->endp,
+                              (ndiffs + 1) * (keys - 1)))
+                       goto corrupt;
+       }
+       ret = 0;
+       goto out;
+
+corrupt:
+       zilog_error("firmware is corrupt\n");
+       fw_unload_locked();
+       ret = -EFAULT;
+
+out:
+       mutex_unlock(&tx_data_lock);
+       return ret;
+}
+
+/* initialise the IR TX device */
+static int tx_init(struct IR *ir)
+{
+       int ret;
+
+       /* Load 'firmware' */
+       ret = fw_load(ir);
+       if (ret != 0)
+               return ret;
+
+       /* Send boot block */
+       ret = send_boot_data(ir);
+       if (ret != 0)
+               return ret;
+       ir->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 = (struct IR *)filep->private_data;
+       unsigned char buf[ir->buf.chunk_size];
+       int ret = 0, written = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dprintk("read called\n");
+       if (ir->c_rx.addr == 0)
+               return -ENODEV;
+
+       if (mutex_lock_interruptible(&ir->buf_lock))
+               return -ERESTARTSYS;
+
+       if (n % ir->buf.chunk_size) {
+               dprintk("read result = -EINVAL\n");
+               mutex_unlock(&ir->buf_lock);
+               return -EINVAL;
+       }
+
+       /*
+        * 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(&ir->buf.wait_poll, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       /*
+        * while we didn't provide 'length' bytes, device is opened in blocking
+        * mode and 'copy_to_user' is happy, wait for data.
+        */
+       while (written < n && ret == 0) {
+               if (lirc_buffer_empty(&ir->buf)) {
+                       /*
+                        * According to the read(2) man page, 'written' can be
+                        * returned as less than 'n', instead of blocking
+                        * again, returning -EWOULDBLOCK, or returning
+                        * -ERESTARTSYS
+                        */
+                       if (written)
+                               break;
+                       if (filep->f_flags & O_NONBLOCK) {
+                               ret = -EWOULDBLOCK;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               ret = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               } else {
+                       lirc_buffer_read(&ir->buf, buf);
+                       ret = copy_to_user((void *)outbuf+written, buf,
+                                          ir->buf.chunk_size);
+                       written += ir->buf.chunk_size;
+               }
+       }
+
+       remove_wait_queue(&ir->buf.wait_poll, &wait);
+       set_current_state(TASK_RUNNING);
+       mutex_unlock(&ir->buf_lock);
+
+       dprintk("read result = %s (%d)\n",
+               ret ? "-EFAULT" : "OK", ret);
+
+       return ret ? ret : written;
+}
+
+/* send a keypress to the IR TX device */
+static int send_code(struct IR *ir, unsigned int code, unsigned int key)
+{
+       unsigned char data_block[TX_BLOCK_SIZE];
+       unsigned char buf[2];
+       int i, ret;
+
+       /* Get data for the codeset/key */
+       ret = get_key_data(data_block, code, key);
+
+       if (ret == -EPROTO) {
+               zilog_error("failed to get data for code %u, key %u -- check "
+                           "lircd.conf entries\n", code, key);
+               return ret;
+       } else if (ret != 0)
+               return ret;
+
+       /* Send the data block */
+       ret = send_data_block(ir, data_block);
+       if (ret != 0)
+               return ret;
+
+       /* Send data block length? */
+       buf[0] = 0x00;
+       buf[1] = 0x40;
+       ret = i2c_master_send(&ir->c_tx, buf, 2);
+       if (ret != 2) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+       ret = i2c_master_send(&ir->c_tx, buf, 1);
+       if (ret != 1) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Send finished download? */
+       ret = i2c_master_recv(&ir->c_tx, buf, 1);
+       if (ret != 1) {
+               zilog_error("i2c_master_recv failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+       if (buf[0] != 0xA0) {
+               zilog_error("unexpected IR TX response #1: %02x\n",
+                       buf[0]);
+               return -EFAULT;
+       }
+
+       /* Send prepare command? */
+       buf[0] = 0x00;
+       buf[1] = 0x80;
+       ret = i2c_master_send(&ir->c_tx, buf, 2);
+       if (ret != 2) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+#ifdef I2C_HW_B_HDPVR
+       /*
+        * The sleep bits aren't necessary on the HD PVR, and in fact, the
+        * last i2c_master_recv always fails with a -5, so for now, we're
+        * going to skip this whole mess and say we're done on the HD PVR
+        */
+       if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR)
+               goto done;
+#endif
+
+       /*
+        * This bit NAKs until the device is ready, so we retry it
+        * sleeping a bit each time.  This seems to be what the windows
+        * driver does, approximately.
+        * Try for up to 1s.
+        */
+       for (i = 0; i < 20; ++i) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout((50 * HZ + 999) / 1000);
+               ret = i2c_master_send(&ir->c_tx, buf, 1);
+               if (ret == 1)
+                       break;
+               dprintk("NAK expected: i2c_master_send "
+                       "failed with %d (try %d)\n", ret, i+1);
+       }
+       if (ret != 1) {
+               zilog_error("IR TX chip never got ready: last i2c_master_send "
+                           "failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Seems to be an 'ok' response */
+       i = i2c_master_recv(&ir->c_tx, buf, 1);
+       if (i != 1) {
+               zilog_error("i2c_master_recv failed with %d\n", ret);
+               return -EFAULT;
+       }
+       if (buf[0] != 0x80) {
+               zilog_error("unexpected IR TX response #2: %02x\n", buf[0]);
+               return -EFAULT;
+       }
+
+done:
+       /* Oh good, it worked */
+       dprintk("sent code %u, key %u\n", code, key);
+       return 0;
+}
+
+/*
+ * Write a code to the device.  We take in a 32-bit number (an int) and then
+ * decode this to a codeset/key index.  The key data is then decompressed and
+ * sent to the device.  We have a spin lock as per i2c documentation to prevent
+ * multiple concurrent sends which would probably cause the device to explode.
+ */
+static ssize_t write(struct file *filep, const char *buf, size_t n,
+                         loff_t *ppos)
+{
+       struct IR *ir = (struct IR *)filep->private_data;
+       size_t i;
+       int failures = 0;
+
+       if (ir->c_tx.addr == 0)
+               return -ENODEV;
+
+       /* Validate user parameters */
+       if (n % sizeof(int))
+               return -EINVAL;
+
+       /* Lock i2c bus for the duration */
+       mutex_lock(&ir->ir_lock);
+
+       /* Send each keypress */
+       for (i = 0; i < n;) {
+               int ret = 0;
+               int command;
+
+               if (copy_from_user(&command, buf + i, sizeof(command))) {
+                       mutex_unlock(&ir->ir_lock);
+                       return -EFAULT;
+               }
+
+               /* Send boot data first if required */
+               if (ir->need_boot == 1) {
+                       ret = send_boot_data(ir);
+                       if (ret == 0)
+                               ir->need_boot = 0;
+               }
+
+               /* Send the code */
+               if (ret == 0) {
+                       ret = send_code(ir, (unsigned)command >> 16,
+                                           (unsigned)command & 0xFFFF);
+                       if (ret == -EPROTO) {
+                               mutex_unlock(&ir->ir_lock);
+                               return ret;
+                       }
+               }
+
+               /*
+                * Hmm, a failure.  If we've had a few then give up, otherwise
+                * try a reset
+                */
+               if (ret != 0) {
+                       /* Looks like the chip crashed, reset it */
+                       zilog_error("sending to the IR transmitter chip "
+                                   "failed, trying reset\n");
+
+                       if (failures >= 3) {
+                               zilog_error("unable to send to the IR chip "
+                                           "after 3 resets, giving up\n");
+                               mutex_unlock(&ir->ir_lock);
+                               return ret;
+                       }
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout((100 * HZ + 999) / 1000);
+                       ir->need_boot = 1;
+                       ++failures;
+               } else
+                       i += sizeof(int);
+       }
+
+       /* Release i2c bus */
+       mutex_unlock(&ir->ir_lock);
+
+       /* All looks good */
+       return n;
+}
+
+/* copied from lirc_dev */
+static unsigned int poll(struct file *filep, poll_table *wait)
+{
+       struct IR *ir = (struct IR *)filep->private_data;
+       unsigned int ret;
+
+       dprintk("poll called\n");
+       if (ir->c_rx.addr == 0)
+               return -ENODEV;
+
+       mutex_lock(&ir->buf_lock);
+
+       poll_wait(filep, &ir->buf.wait_poll, wait);
+
+       dprintk("poll result = %s\n",
+               lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM");
+
+       ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM);
+
+       mutex_unlock(&ir->buf_lock);
+       return ret;
+}
+
+static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       struct IR *ir = (struct IR *)filep->private_data;
+       int result;
+       unsigned long mode, features = 0;
+
+       if (ir->c_rx.addr != 0)
+               features |= LIRC_CAN_REC_LIRCCODE;
+       if (ir->c_tx.addr != 0)
+               features |= LIRC_CAN_SEND_PULSE;
+
+       switch (cmd) {
+       case LIRC_GET_LENGTH:
+               result = put_user((unsigned long)13,
+                                 (unsigned long *)arg);
+               break;
+       case LIRC_GET_FEATURES:
+               result = put_user(features, (unsigned long *) arg);
+               break;
+       case LIRC_GET_REC_MODE:
+               if (!(features&LIRC_CAN_REC_MASK))
+                       return -ENOSYS;
+
+               result = put_user(LIRC_REC2MODE
+                                 (features&LIRC_CAN_REC_MASK),
+                                 (unsigned long *)arg);
+               break;
+       case LIRC_SET_REC_MODE:
+               if (!(features&LIRC_CAN_REC_MASK))
+                       return -ENOSYS;
+
+               result = get_user(mode, (unsigned long *)arg);
+               if (!result && !(LIRC_MODE2REC(mode) & features))
+                       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;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return result;
+}
+
+/*
+ * Open the IR device.  Get hold of our IR structure and
+ * stash it in private_data for the file
+ */
+static int open(struct inode *node, struct file *filep)
+{
+       struct IR *ir;
+       int ret;
+
+       /* find our IR struct */
+       unsigned minor = MINOR(node->i_rdev);
+       if (minor >= MAX_IRCTL_DEVICES) {
+               dprintk("minor %d: open result = -ENODEV\n",
+                       minor);
+               return -ENODEV;
+       }
+       ir = ir_devices[minor];
+
+       /* 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);
+
+       /* stash our IR struct */
+       filep->private_data = ir;
+
+       return 0;
+}
+
+/* Close the IR device */
+static int close(struct inode *node, struct file *filep)
+{
+       /* find our IR struct */
+       struct IR *ir = (struct IR *)filep->private_data;
+       if (ir == NULL) {
+               zilog_error("close: no private_data attached to the file!\n");
+               return -ENODEV;
+       }
+
+       /* decrement in use count */
+       mutex_lock(&ir->ir_lock);
+       --ir->open;
+       set_use_dec(ir);
+       mutex_unlock(&ir->ir_lock);
+
+       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);
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+
+static const struct i2c_device_id ir_transceiver_id[] = {
+       /* Generic entry for any IR transceiver */
+       { "ir_video", 0 },
+       /* IR device specific entries should be added here */
+       { "ir_tx_z8f0811_haup", 0 },
+       { "ir_rx_z8f0811_haup", 0 },
+       { }
+};
+
+static struct i2c_driver driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "Zilog/Hauppauge i2c IR",
+       },
+       .probe          = ir_probe,
+       .remove         = ir_remove,
+       .command        = ir_command,
+       .id_table       = ir_transceiver_id,
+};
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = lseek,
+       .read           = read,
+       .write          = write,
+       .poll           = poll,
+       .unlocked_ioctl = ioctl,
+       .open           = open,
+       .release        = close
+};
+
+static int ir_remove(struct i2c_client *client)
+{
+       struct IR *ir = i2c_get_clientdata(client);
+
+       mutex_lock(&ir->ir_lock);
+
+       if (ir->have_rx || ir->have_tx) {
+               DECLARE_COMPLETION(tn);
+               DECLARE_COMPLETION(tn2);
+
+               /* end up polling thread */
+               if (ir->task && !IS_ERR(ir->task)) {
+                       ir->t_notify = &tn;
+                       ir->t_notify2 = &tn2;
+                       ir->shutdown = 1;
+                       wake_up_process(ir->task);
+                       complete(&tn2);
+                       wait_for_completion(&tn);
+                       ir->t_notify = NULL;
+                       ir->t_notify2 = NULL;
+               }
+
+       } else {
+               mutex_unlock(&ir->ir_lock);
+               zilog_error("%s: detached from something we didn't "
+                           "attach to\n", __func__);
+               return -ENODEV;
+       }
+
+       /* unregister lirc driver */
+       if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
+               lirc_unregister_driver(ir->l.minor);
+               ir_devices[ir->l.minor] = NULL;
+       }
+
+       /* free memory */
+       lirc_buffer_free(&ir->buf);
+       mutex_unlock(&ir->ir_lock);
+       kfree(ir);
+
+       return 0;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct IR *ir = NULL;
+       struct i2c_adapter *adap = client->adapter;
+       char buf;
+       int ret;
+       int have_rx = 0, have_tx = 0;
+
+       dprintk("%s: adapter id=0x%x, client addr=0x%02x\n",
+               __func__, adap->id, client->addr);
+
+       /*
+        * The external IR receiver is at i2c address 0x71.
+        * The IR transmitter is at 0x70.
+        */
+       client->addr = 0x70;
+
+       if (!disable_tx) {
+               if (i2c_master_recv(client, &buf, 1) == 1)
+                       have_tx = 1;
+               dprintk("probe 0x70 @ %s: %s\n",
+                       adap->name, have_tx ? "success" : "failed");
+       }
+
+       if (!disable_rx) {
+               client->addr = 0x71;
+               if (i2c_master_recv(client, &buf, 1) == 1)
+                       have_rx = 1;
+               dprintk("probe 0x71 @ %s: %s\n",
+                       adap->name, have_rx ? "success" : "failed");
+       }
+
+       if (!(have_rx || have_tx)) {
+               zilog_error("%s: no devices found\n", adap->name);
+               goto out_nodev;
+       }
+
+       printk(KERN_INFO "lirc_zilog: chip found with %s\n",
+               have_rx && have_tx ? "RX and TX" :
+                       have_rx ? "RX only" : "TX only");
+
+       ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+
+       if (!ir)
+               goto out_nomem;
+
+       ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2);
+       if (ret)
+               goto out_nomem;
+
+       mutex_init(&ir->ir_lock);
+       mutex_init(&ir->buf_lock);
+       ir->need_boot = 1;
+
+       memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+       ir->l.minor = -1;
+
+       /* I2C attach to device */
+       i2c_set_clientdata(client, ir);
+
+       /* initialise RX device */
+       if (have_rx) {
+               DECLARE_COMPLETION(tn);
+               memcpy(&ir->c_rx, client, sizeof(struct i2c_client));
+
+               ir->c_rx.addr = 0x71;
+               strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME,
+                       I2C_NAME_SIZE);
+
+               /* try to fire up polling thread */
+               ir->t_notify = &tn;
+               ir->task = kthread_run(lirc_thread, ir, "lirc_zilog");
+               if (IS_ERR(ir->task)) {
+                       ret = PTR_ERR(ir->task);
+                       zilog_error("lirc_register_driver: cannot run "
+                                   "poll thread %d\n", ret);
+                       goto err;
+               }
+               wait_for_completion(&tn);
+               ir->t_notify = NULL;
+               ir->have_rx = 1;
+       }
+
+       /* initialise TX device */
+       if (have_tx) {
+               memcpy(&ir->c_tx, client, sizeof(struct i2c_client));
+               ir->c_tx.addr = 0x70;
+               strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME,
+                       I2C_NAME_SIZE);
+               ir->have_tx = 1;
+       }
+
+       /* set lirc_dev stuff */
+       ir->l.code_length = 13;
+       ir->l.rbuf        = &ir->buf;
+       ir->l.fops        = &lirc_fops;
+       ir->l.data        = ir;
+       ir->l.minor       = minor;
+       ir->l.dev         = &adap->dev;
+       ir->l.sample_rate = 0;
+
+       /* register with lirc */
+       ir->l.minor = lirc_register_driver(&ir->l);
+       if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
+               zilog_error("ir_attach: \"minor\" must be between 0 and %d "
+                           "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor);
+               ret = -EBADRQC;
+               goto err;
+       }
+
+       /* store this for getting back in open() later on */
+       ir_devices[ir->l.minor] = ir;
+
+       /*
+        * 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.
+        */
+       if (have_tx) {
+               /* Special TX init */
+               ret = tx_init(ir);
+               if (ret != 0)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       /* undo everything, hopefully... */
+       if (ir->c_rx.addr)
+               ir_remove(&ir->c_rx);
+       if (ir->c_tx.addr)
+               ir_remove(&ir->c_tx);
+       return ret;
+
+out_nodev:
+       zilog_error("no device found\n");
+       return -ENODEV;
+
+out_nomem:
+       zilog_error("memory allocation failure\n");
+       kfree(ir);
+       return -ENOMEM;
+}
+
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+       /* nothing */
+       return 0;
+}
+
+static int __init zilog_init(void)
+{
+       int ret;
+
+       zilog_notify("Zilog/Hauppauge IR driver initializing\n");
+
+       mutex_init(&tx_data_lock);
+
+       request_module("firmware_class");
+
+       ret = i2c_add_driver(&driver);
+       if (ret)
+               zilog_error("initialization failed\n");
+       else
+               zilog_notify("initialization complete\n");
+
+       return ret;
+}
+
+static void __exit zilog_exit(void)
+{
+       i2c_del_driver(&driver);
+       /* if loaded */
+       fw_unload();
+       zilog_notify("Zilog/Hauppauge IR driver unloaded\n");
+}
+
+module_init(zilog_init);
+module_exit(zilog_exit);
+
+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
+MODULE_LICENSE("GPL");
+/* for compat with old name, which isn't all that accurate anymore */
+MODULE_ALIAS("lirc_pvr150");
+
+module_param(minor, int, 0444);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(disable_rx, bool, 0644);
+MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device");
+
+module_param(disable_tx, bool, 0644);
+MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device");
index 3657e33e88178694daf970d930f77a17e0b193ad..c725356cc3466ec5963290415765aab5fb50188a 100644 (file)
@@ -26,8 +26,8 @@ config VIDEO_TM6000_ALSA
          module will be called tm6000-alsa.
 
 config VIDEO_TM6000_DVB
-       bool "DVB Support for tm6000 based TV cards"
-       depends on VIDEO_TM6000 && DVB_CORE && EXPERIMENTAL
+       tristate "DVB Support for tm6000 based TV cards"
+       depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
        select DVB_ZL10353
        ---help---
          This adds support for DVB cards based on the tm5600/tm6000 chip.
index 93370fccc073b83540eb3998f20456803f2569b7..77e06bfd2c466cae63ebe0b2f89372393f655ea1 100644 (file)
@@ -2,14 +2,12 @@ tm6000-objs := tm6000-cards.o \
                   tm6000-core.o  \
                   tm6000-i2c.o   \
                   tm6000-video.o \
-                  tm6000-stds.o
-
-ifeq ($(CONFIG_VIDEO_TM6000_DVB),y)
-tm6000-objs += tm6000-dvb.o
-endif
+                  tm6000-stds.o \
+                  tm6000-input.o
 
 obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
 obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
 
 EXTRA_CFLAGS = -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
index 273e26ede650415f44f019c250cf8f003daab63c..087137d9164deb1dbf17ba110a0686e7669c6926 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 #include <asm/delay.h>
 #include <sound/core.h>
                printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
        } while (0)
 
-/****************************************************************************
-       Data type declarations - Can be moded to a header file later
- ****************************************************************************/
-
-struct snd_tm6000_card {
-       struct snd_card            *card;
-
-       spinlock_t                 reg_lock;
-
-       atomic_t                   count;
-
-       unsigned int               period_size;
-       unsigned int               num_periods;
-
-       struct tm6000_core         *core;
-       struct tm6000_buffer       *buf;
-
-       int                        bufsize;
-
-       struct snd_pcm_substream *substream;
-};
-
-
 /****************************************************************************
                        Module global static vars
  ****************************************************************************/
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
+
 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(enable, bool, NULL, 0444);
@@ -100,11 +78,15 @@ 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_audio_bitrate(core, 48000);
+
        tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
 
        return 0;
@@ -129,19 +111,39 @@ static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
        return 0;
 }
 
-static int dsp_buffer_free(struct snd_tm6000_card *chip)
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
 {
-       BUG_ON(!chip->bufsize);
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
 
        dprintk(2, "Freeing buffer\n");
 
-       /* FIXME: Frees buffer */
+       vfree(substream->runtime->dma_area);
+       substream->runtime->dma_area = NULL;
+       substream->runtime->dma_bytes = 0;
+}
 
-       chip->bufsize = 0;
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       dprintk(2, "Allocating buffer\n");
+
+       if (substream->runtime->dma_area) {
+               if (substream->runtime->dma_bytes > size)
+                       return 0;
+               dsp_buffer_free(substream);
+       }
 
-       return 0;
+       substream->runtime->dma_area = vmalloc(size);
+       if (!substream->runtime->dma_area)
+               return -ENOMEM;
+
+       substream->runtime->dma_bytes = size;
+
+       return 0;
 }
 
+
 /****************************************************************************
                                ALSA PCM Interface
  ****************************************************************************/
@@ -158,16 +160,16 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates =                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
-       .rate_min =             44100,
+       .rates =                SNDRV_PCM_RATE_48000,
+       .rate_min =             48000,
        .rate_max =             48000,
        .channels_min = 2,
        .channels_max = 2,
-       .period_bytes_min = DEFAULT_FIFO_SIZE/4,
-       .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+       .period_bytes_min = 62720,
+       .period_bytes_max = 62720,
        .periods_min = 1,
        .periods_max = 1024,
-       .buffer_bytes_max = (1024*1024),
+       .buffer_bytes_max = 62720 * 8,
 };
 
 /*
@@ -202,29 +204,64 @@ static int snd_tm6000_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+       struct snd_tm6000_card *chip = core->adev;
+       struct snd_pcm_substream *substream = chip->substream;
+       struct snd_pcm_runtime *runtime;
+       int period_elapsed = 0;
+       unsigned int stride, buf_pos;
+
+       if (!size || !substream)
+               return -EINVAL;
+
+       runtime = substream->runtime;
+       if (!runtime || !runtime->dma_area)
+               return -EINVAL;
+
+       buf_pos = chip->buf_pos;
+       stride = runtime->frame_bits >> 3;
+
+       dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+               runtime->dma_area, buf_pos,
+               (unsigned int)runtime->buffer_size, stride);
+
+       if (buf_pos + size >= runtime->buffer_size * stride) {
+               unsigned int cnt = runtime->buffer_size * stride - buf_pos;
+               memcpy(runtime->dma_area + buf_pos, buf, cnt);
+               memcpy(runtime->dma_area, buf + cnt, size - cnt);
+       } else
+               memcpy(runtime->dma_area + buf_pos, buf, size);
+
+       chip->buf_pos += size;
+       if (chip->buf_pos >= runtime->buffer_size * stride)
+               chip->buf_pos -= runtime->buffer_size * stride;
+
+       chip->period_pos += size;
+       if (chip->period_pos >= runtime->period_size) {
+               chip->period_pos -= runtime->period_size;
+               period_elapsed = 1;
+       }
+
+       if (period_elapsed)
+               snd_pcm_period_elapsed(substream);
+
+       return 0;
+}
+
 /*
  * hw_params callback
  */
 static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *hw_params)
 {
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
-       if (substream->runtime->dma_area) {
-               dsp_buffer_free(chip);
-               substream->runtime->dma_area = NULL;
-       }
-
-       chip->period_size = params_period_bytes(hw_params);
-       chip->num_periods = params_periods(hw_params);
-       chip->bufsize = chip->period_size * params_periods(hw_params);
-
-       BUG_ON(!chip->bufsize);
+       int size, rc;
 
-       dprintk(1, "Setting buffer\n");
-
-       /* FIXME: Allocate buffer for audio */
+       size = params_period_bytes(hw_params) * params_periods(hw_params);
 
+       rc = dsp_buffer_alloc(substream, size);
+       if (rc < 0)
+               return rc;
 
        return 0;
 }
@@ -234,13 +271,9 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
  */
 static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
 {
-
        struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
 
-       if (substream->runtime->dma_area) {
-               dsp_buffer_free(chip);
-               substream->runtime->dma_area = NULL;
-       }
+       _tm6000_stop_audio_dma(chip);
 
        return 0;
 }
@@ -250,6 +283,11 @@ static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
  */
 static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
 {
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       chip->buf_pos = 0;
+       chip->period_pos = 0;
+
        return 0;
 }
 
@@ -287,12 +325,8 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       u16 count;
-
-       count = atomic_read(&chip->count);
 
-       return runtime->period_size * (count & (runtime->periods-1));
+       return chip->buf_pos;
 }
 
 /*
@@ -312,21 +346,6 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = {
 /*
  * create a PCM device
  */
-static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
-                                   int device, char *name)
-{
-       int err;
-       struct snd_pcm *pcm;
-
-       err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
-       if (err < 0)
-               return err;
-       pcm->private_data = chip;
-       strcpy(pcm->name, name);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
-
-       return 0;
-}
 
 /* FIXME: Control interface - How to control volume/mute? */
 
@@ -337,27 +356,41 @@ static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
 /*
  * Alsa Constructor - Component probe
  */
-
-int tm6000_audio_init(struct tm6000_core *dev, int idx)
+int tm6000_audio_init(struct tm6000_core *dev)
 {
-       struct snd_card         *card;
-       struct snd_tm6000_card  *chip;
-       int                     rc, len;
-       char                    component[14];
+       struct snd_card         *card;
+       struct snd_tm6000_card  *chip;
+       int                     rc;
+       static int              devnr;
+       char                    component[14];
+       struct snd_pcm          *pcm;
+
+       if (!dev)
+               return 0;
 
-       if (idx >= SNDRV_CARDS)
+       if (devnr >= SNDRV_CARDS)
                return -ENODEV;
 
-       if (!enable[idx])
+       if (!enable[devnr])
                return -ENOENT;
 
-       rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+       rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
        if (rc < 0) {
-               snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+               snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
                return rc;
        }
+       strcpy(card->driver, "tm6000-alsa");
+       strcpy(card->shortname, "TM5600/60x0");
+       sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+               dev->udev->bus->busnum, dev->udev->devnum);
+
+       sprintf(component, "USB%04x:%04x",
+               le16_to_cpu(dev->udev->descriptor.idVendor),
+               le16_to_cpu(dev->udev->descriptor.idProduct));
+       snd_component_add(card, component);
+       snd_card_set_dev(card, &dev->udev->dev);
 
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
        if (!chip) {
                rc = -ENOMEM;
                goto error;
@@ -365,45 +398,24 @@ int tm6000_audio_init(struct tm6000_core *dev, int idx)
 
        chip->core = dev;
        chip->card = card;
+       dev->adev = chip;
+       spin_lock_init(&chip->reg_lock);
 
-       strcpy(card->driver, "tm6000-alsa");
-       sprintf(component, "USB%04x:%04x",
-               le16_to_cpu(dev->udev->descriptor.idVendor),
-               le16_to_cpu(dev->udev->descriptor.idProduct));
-       snd_component_add(card, component);
-
-       if (dev->udev->descriptor.iManufacturer)
-               len = usb_string(dev->udev,
-                                dev->udev->descriptor.iManufacturer,
-                                card->longname, sizeof(card->longname));
-       else
-               len = 0;
-
-       if (len > 0)
-               strlcat(card->longname, " ", sizeof(card->longname));
-
-       strlcat(card->longname, card->shortname, sizeof(card->longname));
-
-       len = strlcat(card->longname, " at ", sizeof(card->longname));
-
-       if (len < sizeof(card->longname))
-               usb_make_path(dev->udev, card->longname + len,
-                             sizeof(card->longname) - len);
-
-       strlcat(card->longname,
-               dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
-               dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
-                                                          ", high speed",
-               sizeof(card->longname));
-
-       rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
+       rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
        if (rc < 0)
                goto error;
 
+       pcm->info_flags = 0;
+       pcm->private_data = chip;
+       strcpy(pcm->name, "Trident TM5600/60x0");
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
        rc = snd_card_register(card);
        if (rc < 0)
                goto error;
 
+       dprintk(1,"Registered audio driver for %s\n", card->longname);
 
        return 0;
 
@@ -414,14 +426,31 @@ error:
 
 static int tm6000_audio_fini(struct tm6000_core *dev)
 {
+       struct snd_tm6000_card  *chip = dev->adev;
+
+       if (!dev)
+               return 0;
+
+       if (!chip)
+               return 0;
+
+       if (!chip->card)
+               return 0;
+
+       snd_card_free(chip->card);
+       chip->card = NULL;
+       kfree(chip);
+       dev->adev = NULL;
+
        return 0;
 }
 
 struct tm6000_ops audio_ops = {
-       .id     = TM6000_AUDIO,
+       .type   = TM6000_AUDIO,
        .name   = "TM6000 Audio Extension",
        .init   = tm6000_audio_init,
        .fini   = tm6000_audio_fini,
+       .fillbuf = tm6000_fillbuf,
 };
 
 static int __init tm6000_alsa_register(void)
index 6a9ae40c7c6dac2a2b60c5afa06e05ab2f928986..9d091c34991b24986db43c51bd79dbc4bef302e9 100644 (file)
@@ -29,6 +29,7 @@
 #include <media/tuner.h>
 #include <media/tvaudio.h>
 #include <media/i2c-addr.h>
+#include <media/rc-map.h>
 
 #include "tm6000.h"
 #include "tm6000-regs.h"
@@ -69,6 +70,8 @@ struct tm6000_board {
        int             demod_addr;     /* demodulator address */
 
        struct tm6000_gpio gpio;
+
+       char            *ir_codes;
 };
 
 struct tm6000_board tm6000_boards[] = {
@@ -276,6 +279,7 @@ struct tm6000_board tm6000_boards[] = {
                        .dvb_led        = TM6010_GPIO_5,
                        .ir             = TM6010_GPIO_0,
                },
+               .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
        },
        [TM6010_BOARD_TWINHAN_TU501] = {
                .name         = "Twinhan TU501(704D1)",
@@ -347,7 +351,7 @@ int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
        }
        return (rc);
 }
-
+EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
 
 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
 
@@ -361,6 +365,8 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
 
        switch (command) {
        case XC2028_RESET_CLK:
+               tm6000_ir_wait(dev, 0);
+
                tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
                                        0x02, arg);
                msleep(10);
@@ -410,13 +416,14 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
                                msleep(130);
                                break;
                        }
+
+                       tm6000_ir_wait(dev, 1);
                        break;
                case 1:
                        tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
                                                0x02, 0x01);
                        msleep(10);
                        break;
-
                case 2:
                        rc = tm6000_i2c_reset(dev, 100);
                        break;
@@ -424,6 +431,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
        }
        return rc;
 }
+EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
 
 int tm6000_cards_setup(struct tm6000_core *dev)
 {
@@ -635,6 +643,8 @@ static int tm6000_init_dev(struct tm6000_core *dev)
 
        dev->gpio = tm6000_boards[dev->model].gpio;
 
+       dev->ir_codes = tm6000_boards[dev->model].ir_codes;
+
        dev->demod_addr = tm6000_boards[dev->model].demod_addr;
 
        dev->caps = tm6000_boards[dev->model].caps;
@@ -681,31 +691,13 @@ static int tm6000_init_dev(struct tm6000_core *dev)
                goto err;
 
        tm6000_add_into_devlist(dev);
-
        tm6000_init_extension(dev);
 
-       if (dev->caps.has_dvb) {
-               dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
-               if (!dev->dvb) {
-                       rc = -ENOMEM;
-                       goto err2;
-               }
+       tm6000_ir_init(dev);
 
-#ifdef CONFIG_VIDEO_TM6000_DVB
-               rc = tm6000_dvb_register(dev);
-               if (rc < 0) {
-                       kfree(dev->dvb);
-                       dev->dvb = NULL;
-                       goto err2;
-               }
-#endif
-       }
        mutex_unlock(&dev->lock);
        return 0;
 
-err2:
-       v4l2_device_unregister(&dev->v4l2_dev);
-
 err:
        mutex_unlock(&dev->lock);
        return rc;
@@ -724,7 +716,7 @@ static void get_max_endpoint(struct usb_device *udev,
        unsigned int size = tmp & 0x7ff;
 
        if (udev->speed == USB_SPEED_HIGH)
-               size = size * hb_mult (tmp);
+               size = size * hb_mult(tmp);
 
        if (size > tm_ep->maxsize) {
                tm_ep->endp = curr_e;
@@ -848,6 +840,19 @@ static int tm6000_usb_probe(struct usb_interface *interface,
                                                         &dev->isoc_out);
                                }
                                break;
+                       case USB_ENDPOINT_XFER_INT:
+                               if (!dir_out) {
+                                       get_max_endpoint(usbdev,
+                                                       &interface->altsetting[i],
+                                                       "INT IN", e,
+                                                       &dev->int_in);
+                               } else {
+                                       get_max_endpoint(usbdev,
+                                                       &interface->altsetting[i],
+                                                       "INT OUT", e,
+                                                       &dev->int_out);
+                               }
+                               break;
                        }
                }
        }
@@ -906,12 +911,7 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
 
        mutex_lock(&dev->lock);
 
-#ifdef CONFIG_VIDEO_TM6000_DVB
-       if (dev->dvb) {
-               tm6000_dvb_unregister(dev);
-               kfree(dev->dvb);
-       }
-#endif
+       tm6000_ir_fini(dev);
 
        if (dev->gpio.power_led) {
                switch (dev->model) {
@@ -942,8 +942,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
 
        usb_put_dev(dev->udev);
 
-       tm6000_remove_from_devlist(dev);
        tm6000_close_extension(dev);
+       tm6000_remove_from_devlist(dev);
 
        mutex_unlock(&dev->lock);
        kfree(dev);
index c3690e3580da05a002ab272a042804dfda78886f..cded411d8bba552eff047f068eefbf9adb3720d4 100644 (file)
 
 #define USB_TIMEOUT    5*HZ /* ms */
 
-int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
-                          u16 value, u16 index, u8 *buf, u16 len)
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
+                         u16 value, u16 index, u8 *buf, u16 len)
 {
        int          ret, i;
        unsigned int pipe;
-       static int   ini=0, last=0, n=0;
-       u8           *data=NULL;
+       static int   ini = 0, last = 0, n = 0;
+       u8           *data = NULL;
 
        if (len)
                data = kzalloc(len, GFP_KERNEL);
 
 
        if (req_type & USB_DIR_IN)
-               pipe=usb_rcvctrlpipe(dev->udev, 0);
+               pipe = usb_rcvctrlpipe(dev->udev, 0);
        else {
-               pipe=usb_sndctrlpipe(dev->udev, 0);
+               pipe = usb_sndctrlpipe(dev->udev, 0);
                memcpy(data, buf, len);
        }
 
        if (tm6000_debug & V4L2_DEBUG_I2C) {
                if (!ini)
-                       last=ini=jiffies;
+                       last = ini = jiffies;
 
                printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
 
-               printk( "%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
-                       (req_type & USB_DIR_IN)?" IN":"OUT",
+               printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+                       (req_type & USB_DIR_IN) ? " IN" : "OUT",
                        jiffies_to_msecs(jiffies-last),
                        jiffies_to_msecs(jiffies-ini),
-                       req_type, req,value&0xff,value>>8, index&0xff, index>>8,
-                       len&0xff, len>>8);
-               last=jiffies;
+                       req_type, req, value&0xff, value>>8, index&0xff,
+                       index>>8, len&0xff, len>>8);
+               last = jiffies;
                n++;
 
-               if ( !(req_type & USB_DIR_IN) ) {
+               if (!(req_type & USB_DIR_IN)) {
                        printk(">>> ");
-                       for (i=0;i<len;i++) {
-                               printk(" %02x",buf[i]);
-                       }
+                       for (i = 0; i < len; i++)
+                               printk(" %02x", buf[i]);
                printk("\n");
                }
        }
 
-       ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, data,
-                             len, USB_TIMEOUT);
+       ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
+                             data, len, USB_TIMEOUT);
 
        if (req_type &  USB_DIR_IN)
                memcpy(buf, data, len);
 
        if (tm6000_debug & V4L2_DEBUG_I2C) {
-               if (ret<0) {
+               if (ret < 0) {
                        if (req_type &  USB_DIR_IN)
-                               printk("<<< (len=%d)\n",len);
+                               printk("<<< (len=%d)\n", len);
 
                        printk("%s: Error #%d\n", __FUNCTION__, ret);
                } else if (req_type &  USB_DIR_IN) {
                        printk("<<< ");
-                       for (i=0;i<len;i++) {
-                               printk(" %02x",buf[i]);
-                       }
+                       for (i = 0; i < len; i++)
+                               printk(" %02x", buf[i]);
                        printk("\n");
                }
        }
@@ -103,52 +101,52 @@ int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
        return ret;
 }
 
-int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
        return
-               tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
-                                      req, value, index, NULL, 0);
+               tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+                                     req, value, index, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(tm6000_set_reg);
 
-int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
        int rc;
        u8 buf[1];
 
-       rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                      value, index, buf, 1);
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 1);
 
-       if (rc<0)
+       if (rc < 0)
                return rc;
 
        return *buf;
 }
 EXPORT_SYMBOL_GPL(tm6000_get_reg);
 
-int tm6000_get_reg16 (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 rc;
        u8 buf[2];
 
-       rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                      value, index, buf, 2);
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 2);
 
-       if (rc<0)
+       if (rc < 0)
                return rc;
 
        return buf[1]|buf[0]<<8;
 }
 
-int tm6000_get_reg32 (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 rc;
        u8 buf[4];
 
-       rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                      value, index, buf, 4);
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 4);
 
-       if (rc<0)
+       if (rc < 0)
                return rc;
 
        return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
@@ -188,7 +186,7 @@ void tm6000_set_fourcc_format(struct tm6000_core *dev)
        }
 }
 
-int tm6000_init_analog_mode (struct tm6000_core *dev)
+int tm6000_init_analog_mode(struct tm6000_core *dev)
 {
        if (dev->dev_type == TM6010) {
                int val;
@@ -294,12 +292,10 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
                /* Enables soft reset */
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
 
-               if (dev->scaler) {
+               if (dev->scaler)
                        tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
-               } else {
-                       /* Enable Hfilter and disable TS Drop err */
+               else    /* Enable Hfilter and disable TS Drop err */
                        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);
@@ -332,13 +328,13 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
        /*FIXME: Hack!!! */
        struct v4l2_frequency f;
        mutex_lock(&dev->lock);
-       f.frequency=dev->freq;
+       f.frequency = dev->freq;
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
        mutex_unlock(&dev->lock);
 
        msleep(100);
-       tm6000_set_standard (dev, &dev->norm);
-       tm6000_set_audio_bitrate (dev,48000);
+       tm6000_set_standard(dev, &dev->norm);
+       tm6000_set_audio_bitrate(dev, 48000);
 
        /* switch dvb led off */
        if (dev->gpio.dvb_led) {
@@ -349,7 +345,7 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
        return 0;
 }
 
-int tm6000_init_digital_mode (struct tm6000_core *dev)
+int tm6000_init_digital_mode(struct tm6000_core *dev)
 {
        if (dev->dev_type == TM6010) {
                int val;
@@ -366,10 +362,8 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
                tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
                tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
-               tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
-               printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
-
-
+               tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
+               printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]);
        } else  {
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
@@ -377,7 +371,7 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
                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, REQ_07_SET_GET_AVREG, 0x00eb, 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);
@@ -388,14 +382,14 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
 
                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, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
                msleep(50);
 
-               tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
                msleep(50);
-               tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
                msleep(50);
-               tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
                msleep(100);
        }
 
@@ -407,6 +401,7 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
 
        return 0;
 }
+EXPORT_SYMBOL(tm6000_init_digital_mode);
 
 struct reg_init {
        u8 req;
@@ -566,9 +561,9 @@ struct reg_init tm6010_init_tab[] = {
        { TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
 };
 
-int tm6000_init (struct tm6000_core *dev)
+int tm6000_init(struct tm6000_core *dev)
 {
-       int board, rc=0, i, size;
+       int board, rc = 0, i, size;
        struct reg_init *tab;
 
        if (dev->dev_type == TM6010) {
@@ -580,12 +575,12 @@ int tm6000_init (struct tm6000_core *dev)
        }
 
        /* Load board's initialization table */
-       for (i=0; i< size; i++) {
-               rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
-               if (rc<0) {
-                       printk (KERN_ERR "Error %i while setting req %d, "
-                                        "reg %d to value %d\n", rc,
-                                        tab[i].req,tab[i].reg, tab[i].val);
+       for (i = 0; i < size; i++) {
+               rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
+               if (rc < 0) {
+                       printk(KERN_ERR "Error %i while setting req %d, "
+                                       "reg %d to value %d\n", rc,
+                                       tab[i].req, tab[i].reg, tab[i].val);
                        return rc;
                }
        }
@@ -593,12 +588,11 @@ int tm6000_init (struct tm6000_core *dev)
        msleep(5); /* Just to be conservative */
 
        /* Check board version - maybe 10Moons specific */
-       board=tm6000_get_reg32 (dev, REQ_40_GET_VERSION, 0, 0);
-       if (board >=0) {
-               printk (KERN_INFO "Board version = 0x%08x\n",board);
-       } else {
-               printk (KERN_ERR "Error %i while retrieving board version\n",board);
-       }
+       board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
+       if (board >= 0)
+               printk(KERN_INFO "Board version = 0x%08x\n", board);
+       else
+               printk(KERN_ERR "Error %i while retrieving board version\n", board);
 
        rc = tm6000_cards_setup(dev);
 
@@ -609,23 +603,32 @@ int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
 {
        int val;
 
-       val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
-printk("Original value=%d\n",val);
-       if (val<0)
+       if (dev->dev_type == TM6010) {
+               val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0);
+               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);
+               if (val < 0)
+                       return val;
+       }
+
+       val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
+       if (val < 0)
                return val;
 
        val &= 0x0f;            /* Preserve the audio input control bits */
        switch (bitrate) {
        case 44100:
-               val|=0xd0;
-               dev->audio_bitrate=bitrate;
+               val |= 0xd0;
+               dev->audio_bitrate = bitrate;
                break;
        case 48000:
-               val|=0x60;
-               dev->audio_bitrate=bitrate;
+               val |= 0x60;
+               dev->audio_bitrate = bitrate;
                break;
        }
-       val=tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+       val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val);
 
        return val;
 }
@@ -659,6 +662,23 @@ void tm6000_add_into_devlist(struct tm6000_core *dev)
 static LIST_HEAD(tm6000_extension_devlist);
 static DEFINE_MUTEX(tm6000_extension_devlist_lock);
 
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+                       char *buf, int size)
+{
+       struct tm6000_ops *ops = NULL;
+
+       /* FIXME: tm6000_extension_devlist_lock should be a spinlock */
+
+       if (!list_empty(&tm6000_extension_devlist)) {
+               list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+                       if (ops->fillbuf && ops->type == type)
+                               ops->fillbuf(dev, buf, size);
+               }
+       }
+
+       return 0;
+}
+
 int tm6000_register_extension(struct tm6000_ops *ops)
 {
        struct tm6000_core *dev = NULL;
@@ -667,10 +687,10 @@ int tm6000_register_extension(struct tm6000_ops *ops)
        mutex_lock(&tm6000_extension_devlist_lock);
        list_add_tail(&ops->next, &tm6000_extension_devlist);
        list_for_each_entry(dev, &tm6000_devlist, devlist) {
-               if (dev)
-                       ops->init(dev);
+               ops->init(dev);
+               printk(KERN_INFO "%s: Initialized (%s) extension\n",
+                      dev->name, ops->name);
        }
-       printk(KERN_INFO "tm6000: Initialized (%s) extension\n", ops->name);
        mutex_unlock(&tm6000_extension_devlist_lock);
        mutex_unlock(&tm6000_devlist_mutex);
        return 0;
index 86c1c8b5f25aad41cc1bd82f7f62959493147538..f501edccf9c4c8f4327d0e8aab82853c3c60587a 100644 (file)
 #include "tuner-xc2028.h"
 #include "xc5000.h"
 
-static void inline print_err_status (struct tm6000_core *dev,
-                                    int packet, int status)
+MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
+                       "{{Trident, tm6000},"
+                       "{{Trident, tm6010}");
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug message");
+
+static inline void print_err_status(struct tm6000_core *dev,
+                                   int packet, int status)
 {
        char *errmsg = "Unknown";
 
-       switch(status) {
+       switch (status) {
        case -ENOENT:
                errmsg = "unlinked synchronuously";
                break;
@@ -62,7 +75,7 @@ static void inline print_err_status (struct tm6000_core *dev,
                errmsg = "Device does not respond";
                break;
        }
-       if (packet<0) {
+       if (packet < 0) {
                dprintk(dev, 1, "URB status %d [%s].\n",
                        status, errmsg);
        } else {
@@ -74,19 +87,17 @@ static void inline print_err_status (struct tm6000_core *dev,
 static void tm6000_urb_received(struct urb *urb)
 {
        int ret;
-       struct tm6000_coredev = urb->context;
+       struct tm6000_core *dev = urb->context;
 
-       if(urb->status != 0) {
-               print_err_status (dev,0,urb->status);
-       }
-       else if(urb->actual_length>0){
+       if (urb->status != 0)
+               print_err_status(dev, 0, urb->status);
+       else if (urb->actual_length > 0)
                dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
                                                   urb->actual_length);
-       }
 
-       if(dev->dvb->streams > 0) {
+       if (dev->dvb->streams > 0) {
                ret = usb_submit_urb(urb, GFP_ATOMIC);
-               if(ret < 0) {
+               if (ret < 0) {
                        printk(KERN_ERR "tm6000:  error %s\n", __FUNCTION__);
                        kfree(urb->transfer_buffer);
                        usb_free_urb(urb);
@@ -100,7 +111,7 @@ int tm6000_start_stream(struct tm6000_core *dev)
        unsigned int pipe, size;
        struct tm6000_dvb *dvb = dev->dvb;
 
-       printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
+       printk(KERN_INFO "tm6000: got start stream request %s\n", __FUNCTION__);
 
        if (dev->mode != TM6000_MODE_DIGITAL) {
                tm6000_init_digital_mode(dev);
@@ -108,7 +119,7 @@ int tm6000_start_stream(struct tm6000_core *dev)
        }
 
        dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if(dvb->bulk_urb == NULL) {
+       if (dvb->bulk_urb == NULL) {
                printk(KERN_ERR "tm6000: couldn't allocate urb\n");
                return -ENOMEM;
        }
@@ -120,7 +131,7 @@ int tm6000_start_stream(struct tm6000_core *dev)
        size = size * 15; /* 512 x 8 or 12 or 15 */
 
        dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
-       if(dvb->bulk_urb->transfer_buffer == NULL) {
+       if (dvb->bulk_urb->transfer_buffer == NULL) {
                usb_free_urb(dvb->bulk_urb);
                printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
                return -ENOMEM;
@@ -132,20 +143,20 @@ int tm6000_start_stream(struct tm6000_core *dev)
                                                 tm6000_urb_received, dev);
 
        ret = usb_clear_halt(dev->udev, pipe);
-       if(ret < 0) {
-               printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__);
+       if (ret < 0) {
+               printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
+                                                       ret, __FUNCTION__);
                return ret;
-       }
-       else {
+       } else
                printk(KERN_ERR "tm6000: pipe resetted\n");
-       }
 
 /*     mutex_lock(&tm6000_driver.open_close_mutex); */
        ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
 
 /*     mutex_unlock(&tm6000_driver.open_close_mutex); */
        if (ret) {
-               printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
+               printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
+                                                                       ret);
 
                kfree(dvb->bulk_urb->transfer_buffer);
                usb_free_urb(dvb->bulk_urb);
@@ -159,10 +170,10 @@ void tm6000_stop_stream(struct tm6000_core *dev)
 {
        struct tm6000_dvb *dvb = dev->dvb;
 
-       if(dvb->bulk_urb) {
-               printk (KERN_INFO "urb killing\n");
+       if (dvb->bulk_urb) {
+               printk(KERN_INFO "urb killing\n");
                usb_kill_urb(dvb->bulk_urb);
-               printk (KERN_INFO "urb buffer free\n");
+               printk(KERN_INFO "urb buffer free\n");
                kfree(dvb->bulk_urb->transfer_buffer);
                usb_free_urb(dvb->bulk_urb);
                dvb->bulk_urb = NULL;
@@ -174,35 +185,34 @@ int tm6000_start_feed(struct dvb_demux_feed *feed)
        struct dvb_demux *demux = feed->demux;
        struct tm6000_core *dev = demux->priv;
        struct tm6000_dvb *dvb = dev->dvb;
-       printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__);
+       printk(KERN_INFO "tm6000: got start feed request %s\n", __FUNCTION__);
 
        mutex_lock(&dvb->mutex);
-       if(dvb->streams == 0) {
+       if (dvb->streams == 0) {
                dvb->streams = 1;
 /*             mutex_init(&tm6000_dev->streming_mutex); */
                tm6000_start_stream(dev);
-       }
-       else {
+       } else
                ++(dvb->streams);
-       }
        mutex_unlock(&dvb->mutex);
 
        return 0;
 }
 
-int tm6000_stop_feed(struct dvb_demux_feed *feed) {
+int tm6000_stop_feed(struct dvb_demux_feed *feed)
+{
        struct dvb_demux *demux = feed->demux;
        struct tm6000_core *dev = demux->priv;
        struct tm6000_dvb *dvb = dev->dvb;
 
-       printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
+       printk(KERN_INFO "tm6000: got stop feed request %s\n", __FUNCTION__);
 
        mutex_lock(&dvb->mutex);
 
-       printk (KERN_INFO "stream %#x\n", dvb->streams);
+       printk(KERN_INFO "stream %#x\n", dvb->streams);
        --(dvb->streams);
-       if(dvb->streams == 0) {
-               printk (KERN_INFO "stop stream\n");
+       if (dvb->streams == 0) {
+               printk(KERN_INFO "stop stream\n");
                tm6000_stop_stream(dev);
 /*             mutex_destroy(&tm6000_dev->streaming_mutex); */
        }
@@ -216,9 +226,9 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
 {
        struct tm6000_dvb *dvb = dev->dvb;
 
-       if(dev->caps.has_zl10353) {
-               struct zl10353_config config =
-                                   {.demod_address = dev->demod_addr,
+       if (dev->caps.has_zl10353) {
+               struct zl10353_config config = {
+                                    .demod_address = dev->demod_addr,
                                     .no_tuner = 1,
                                     .parallel_ts = 1,
                                     .if2 = 45700,
@@ -227,8 +237,7 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
 
                dvb->frontend = dvb_attach(zl10353_attach, &config,
                                                           &dev->i2c_adap);
-       }
-       else {
+       } else {
                printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
                return -1;
        }
@@ -238,7 +247,7 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-int tm6000_dvb_register(struct tm6000_core *dev)
+int register_dvb(struct tm6000_core *dev)
 {
        int ret = -1;
        struct tm6000_dvb *dvb = dev->dvb;
@@ -249,13 +258,13 @@ int tm6000_dvb_register(struct tm6000_core *dev)
 
        /* attach the frontend */
        ret = tm6000_dvb_attach_frontend(dev);
-       if(ret < 0) {
+       if (ret < 0) {
                printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
                goto err;
        }
 
        ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
-                                                         THIS_MODULE, &dev->udev->dev, adapter_nr);
+                                       THIS_MODULE, &dev->udev->dev, adapter_nr);
        dvb->adapter.priv = dev;
 
        if (dvb->frontend) {
@@ -308,9 +317,8 @@ int tm6000_dvb_register(struct tm6000_core *dev)
                        break;
                        }
                }
-       } else {
+       } else
                printk(KERN_ERR "tm6000: no frontend found\n");
-       }
 
        dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
                                                            | DMX_MEMORY_BASED_FILTERING;
@@ -321,7 +329,7 @@ int tm6000_dvb_register(struct tm6000_core *dev)
        dvb->demux.stop_feed = tm6000_stop_feed;
        dvb->demux.write_to_decoder = NULL;
        ret = dvb_dmx_init(&dvb->demux);
-       if(ret < 0) {
+       if (ret < 0) {
                printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
                goto frontend_err;
        }
@@ -331,7 +339,7 @@ int tm6000_dvb_register(struct tm6000_core *dev)
        dvb->dmxdev.capabilities = 0;
 
        ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
-       if(ret < 0) {
+       if (ret < 0) {
                printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
                goto dvb_dmx_err;
        }
@@ -341,7 +349,7 @@ int tm6000_dvb_register(struct tm6000_core *dev)
 dvb_dmx_err:
        dvb_dmx_release(&dvb->demux);
 frontend_err:
-       if(dvb->frontend) {
+       if (dvb->frontend) {
                dvb_frontend_detach(dvb->frontend);
                dvb_unregister_frontend(dvb->frontend);
        }
@@ -351,11 +359,11 @@ err:
        return ret;
 }
 
-void tm6000_dvb_unregister(struct tm6000_core *dev)
+void unregister_dvb(struct tm6000_core *dev)
 {
        struct tm6000_dvb *dvb = dev->dvb;
 
-       if(dvb->bulk_urb != NULL) {
+       if (dvb->bulk_urb != NULL) {
                struct urb *bulk_urb = dvb->bulk_urb;
 
                kfree(bulk_urb->transfer_buffer);
@@ -365,7 +373,7 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
        }
 
 /*     mutex_lock(&tm6000_driver.open_close_mutex); */
-       if(dvb->frontend) {
+       if (dvb->frontend) {
                dvb_frontend_detach(dvb->frontend);
                dvb_unregister_frontend(dvb->frontend);
        }
@@ -375,5 +383,70 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
        dvb_unregister_adapter(&dvb->adapter);
        mutex_destroy(&dvb->mutex);
 /*     mutex_unlock(&tm6000_driver.open_close_mutex); */
+}
 
+static int dvb_init(struct tm6000_core *dev)
+{
+       struct tm6000_dvb *dvb;
+       int rc;
+
+       if (!dev)
+               return 0;
+
+       if (!dev->caps.has_dvb)
+               return 0;
+
+       dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
+       if (!dvb) {
+               printk(KERN_INFO "Cannot allocate memory\n");
+               return -ENOMEM;
+       }
+
+       dev->dvb = dvb;
+
+       rc = register_dvb(dev);
+       if (rc < 0) {
+               kfree(dvb);
+               dev->dvb = NULL;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int dvb_fini(struct tm6000_core *dev)
+{
+       if (!dev)
+               return 0;
+
+       if (!dev->caps.has_dvb)
+               return 0;
+
+       if (dev->dvb) {
+               unregister_dvb(dev);
+               kfree(dev->dvb);
+               dev->dvb = NULL;
+       }
+
+       return 0;
 }
+
+static struct tm6000_ops dvb_ops = {
+       .type   = TM6000_DVB,
+       .name   = "TM6000 dvb Extension",
+       .init   = dvb_init,
+       .fini   = dvb_fini,
+};
+
+static int __init tm6000_dvb_register(void)
+{
+       return tm6000_register_extension(&dvb_ops);
+}
+
+static void __exit tm6000_dvb_unregister(void)
+{
+       tm6000_unregister_extension(&dvb_ops);
+}
+
+module_init(tm6000_dvb_register);
+module_exit(tm6000_dvb_unregister);
index 94ff489a1bbb3396fad0d26edabd5d5525a1b45e..79bc67f0311fc1ffc892207b522cd7c35c9b97da 100644 (file)
@@ -40,7 +40,7 @@ static unsigned int i2c_debug = 0;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-#define i2c_dprintk(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
                        printk(KERN_DEBUG "%s at %s: " fmt, \
                        dev->name, __FUNCTION__ , ##args); } while (0)
 
@@ -171,7 +171,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
                return 0;
        for (i = 0; i < num; i++) {
                addr = (msgs[i].addr << 1) & 0xff;
-               i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
+               i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
                         (msgs[i].flags & I2C_M_RD) ? "read" : "write",
                         i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
                if (msgs[i].flags & I2C_M_RD) {
@@ -235,7 +235,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
 
        return num;
 err:
-       i2c_dprintk(2," ERROR: %i\n", rc);
+       i2c_dprintk(2, " ERROR: %i\n", rc);
        return rc;
 }
 
@@ -266,11 +266,10 @@ static int tm6000_i2c_eeprom(struct tm6000_core *dev,
                if (0 == (i % 16))
                        printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
                printk(" %02x", eedata[i]);
-               if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) {
+               if ((eedata[i] >= ' ') && (eedata[i] <= 'z'))
                        bytes[i%16] = eedata[i];
-               } else {
-                       bytes[i%16]='.';
-               }
+               else
+                       bytes[i%16] = '.';
 
                i++;
 
@@ -305,15 +304,15 @@ static u32 functionality(struct i2c_adapter *adap)
 }
 
 #define mass_write(addr, reg, data...)                                 \
-       { const static u8 _val[] = data;                                \
-       rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR,     \
-       REQ_16_SET_GET_I2C_WR1_RDN,(reg<<8)+addr, 0x00, (u8 *) _val,    \
+       { static const u8 _val[] = data;                                \
+       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,  \
+       REQ_16_SET_GET_I2C_WR1_RDN, (reg<<8)+addr, 0x00, (u8 *) _val,   \
        ARRAY_SIZE(_val));                                              \
-       if (rc<0) {                                                     \
-               printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc);  \
+       if (rc < 0) {                                                   \
+               printk(KERN_ERR "Error on line %d: %d\n", __LINE__, rc);        \
                return rc;                                              \
        }                                                               \
-       msleep (10);                                                    \
+       msleep(10);                                                     \
        }
 
 static struct i2c_algorithm tm6000_algo = {
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
new file mode 100644 (file)
index 0000000..32f7a0a
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+   tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.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 version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include <media/ir-core.h>
+#include <media/ir-common.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
+
+static unsigned int enable_ir = 1;
+module_param(enable_ir, int, 0644);
+MODULE_PARM_DESC(enable_ir, "enable ir (default is enable");
+
+#undef dprintk
+
+#define dprintk(fmt, arg...) \
+       if (ir_debug) { \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+       }
+
+struct tm6000_ir_poll_result {
+       u8 rc_data[4];
+};
+
+struct tm6000_IR {
+       struct tm6000_core      *dev;
+       struct ir_input_dev     *input;
+       struct ir_input_state   ir;
+       char                    name[32];
+       char                    phys[32];
+
+       /* poll expernal decoder */
+       int                     polling;
+       struct delayed_work     work;
+       u8                      wait:1;
+       struct urb              *int_urb;
+       u8                      *urb_data;
+       u8                      key:1;
+
+       int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
+
+       /* IR device properties */
+       struct ir_dev_props     props;
+};
+
+
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!dev->ir)
+               return;
+
+       if (state)
+               ir->wait = 1;
+       else
+               ir->wait = 0;
+}
+
+
+static int tm6000_ir_config(struct tm6000_IR *ir)
+{
+       struct tm6000_core *dev = ir->dev;
+       u8 buf[10];
+       int rc;
+
+       /* hack */
+       buf[0] = 0xff;
+       buf[1] = 0xff;
+       buf[2] = 0xf2;
+       buf[3] = 0x2b;
+       buf[4] = 0x20;
+       buf[5] = 0x35;
+       buf[6] = 0x60;
+       buf[7] = 0x04;
+       buf[8] = 0xc0;
+       buf[9] = 0x08;
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+               USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+       msleep(100);
+
+       if (rc < 0) {
+               printk(KERN_INFO "IR configuration failed");
+               return rc;
+       }
+       return 0;
+}
+
+static void tm6000_ir_urb_received(struct urb *urb)
+{
+       struct tm6000_core *dev = urb->context;
+       struct tm6000_IR *ir = dev->ir;
+       int rc;
+
+       if (urb->status != 0)
+               printk(KERN_INFO "not ready\n");
+       else if (urb->actual_length > 0)
+               memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
+
+       dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
+       ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+
+       ir->key = 1;
+
+       rc = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int default_polling_getkey(struct tm6000_IR *ir,
+                               struct tm6000_ir_poll_result *poll_result)
+{
+       struct tm6000_core *dev = ir->dev;
+       int rc;
+       u8 buf[2];
+
+       if (ir->wait && !&dev->int_in) {
+               poll_result->rc_data[0] = 0xff;
+               return 0;
+       }
+
+       if (&dev->int_in) {
+               poll_result->rc_data[0] = ir->urb_data[0];
+               poll_result->rc_data[1] = ir->urb_data[1];
+       } else {
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+               msleep(10);
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
+               msleep(10);
+
+               rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+                USB_RECIP_DEVICE, REQ_02_GET_IR_CODE, 0, 0, buf, 1);
+
+               msleep(10);
+
+               dprintk("read data=%02x\n", buf[0]);
+               if (rc < 0)
+                       return rc;
+
+               poll_result->rc_data[0] = buf[0];
+       }
+       return 0;
+}
+
+static void tm6000_ir_handle_key(struct tm6000_IR *ir)
+{
+       int result;
+       struct tm6000_ir_poll_result poll_result;
+
+       /* read the registers containing the IR status */
+       result = ir->get_key(ir, &poll_result);
+       if (result < 0) {
+               printk(KERN_INFO "ir->get_key() failed %d\n", result);
+               return;
+       }
+
+       dprintk("ir->get_key result data=%02x %02x\n",
+               poll_result.rc_data[0], poll_result.rc_data[1]);
+
+       if (poll_result.rc_data[0] != 0xff && ir->key == 1) {
+               ir_input_keydown(ir->input->input_dev, &ir->ir,
+                       poll_result.rc_data[0] | poll_result.rc_data[1] << 8);
+
+               ir_input_nokey(ir->input->input_dev, &ir->ir);
+               ir->key = 0;
+       }
+       return;
+}
+
+static void tm6000_ir_work(struct work_struct *work)
+{
+       struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
+
+       tm6000_ir_handle_key(ir);
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+}
+
+static int tm6000_ir_start(void *priv)
+{
+       struct tm6000_IR *ir = priv;
+
+       INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
+       schedule_delayed_work(&ir->work, 0);
+
+       return 0;
+}
+
+static void tm6000_ir_stop(void *priv)
+{
+       struct tm6000_IR *ir = priv;
+
+       cancel_delayed_work_sync(&ir->work);
+}
+
+int tm6000_ir_change_protocol(void *priv, u64 ir_type)
+{
+       struct tm6000_IR *ir = priv;
+
+       ir->get_key = default_polling_getkey;
+
+       tm6000_ir_config(ir);
+       /* TODO */
+       return 0;
+}
+
+int tm6000_ir_init(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir;
+       struct ir_input_dev *ir_input_dev;
+       int err = -ENOMEM;
+       int pipe, size, rc;
+
+       if (!enable_ir)
+               return -ENODEV;
+
+       if (!dev->caps.has_remote)
+               return 0;
+
+       if (!dev->ir_codes)
+               return 0;
+
+       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+       ir_input_dev = kzalloc(sizeof(*ir_input_dev), GFP_KERNEL);
+       ir_input_dev->input_dev = input_allocate_device();
+       if (!ir || !ir_input_dev || !ir_input_dev->input_dev)
+               goto err_out_free;
+
+       /* record handles to ourself */
+       ir->dev = dev;
+       dev->ir = ir;
+
+       ir->input = ir_input_dev;
+
+       /* input einrichten */
+       ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+       ir->props.priv = ir;
+       ir->props.change_protocol = tm6000_ir_change_protocol;
+       ir->props.open = tm6000_ir_start;
+       ir->props.close = tm6000_ir_stop;
+       ir->props.driver_type = RC_DRIVER_SCANCODE;
+
+       ir->polling = 50;
+
+       snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
+                                               dev->name);
+
+       usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+       strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+       tm6000_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+       err = ir_input_init(ir_input_dev->input_dev, &ir->ir, IR_TYPE_OTHER);
+       if (err < 0)
+               goto err_out_free;
+
+       ir_input_dev->input_dev->name = ir->name;
+       ir_input_dev->input_dev->phys = ir->phys;
+       ir_input_dev->input_dev->id.bustype = BUS_USB;
+       ir_input_dev->input_dev->id.version = 1;
+       ir_input_dev->input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+       ir_input_dev->input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+       ir_input_dev->input_dev->dev.parent = &dev->udev->dev;
+
+       if (&dev->int_in) {
+               dprintk("IR over int\n");
+
+               ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+               pipe = usb_rcvintpipe(dev->udev,
+                       dev->int_in.endp->desc.bEndpointAddress
+                       & USB_ENDPOINT_NUMBER_MASK);
+
+               size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+               dprintk("IR max size: %d\n", size);
+
+               ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+               if (ir->int_urb->transfer_buffer == NULL) {
+                       usb_free_urb(ir->int_urb);
+                       goto err_out_stop;
+               }
+               dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+               usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+                       ir->int_urb->transfer_buffer, size,
+                       tm6000_ir_urb_received, dev,
+                       dev->int_in.endp->desc.bInterval);
+               rc = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+               if (rc) {
+                       kfree(ir->int_urb->transfer_buffer);
+                       usb_free_urb(ir->int_urb);
+                       err = rc;
+                       goto err_out_stop;
+               }
+               ir->urb_data = kzalloc(size, GFP_KERNEL);
+       }
+
+       /* ir register */
+       err = ir_input_register(ir->input->input_dev, dev->ir_codes,
+               &ir->props, "tm6000");
+       if (err)
+               goto err_out_stop;
+
+       return 0;
+
+err_out_stop:
+       dev->ir = NULL;
+err_out_free:
+       kfree(ir_input_dev);
+       kfree(ir);
+       return err;
+}
+
+int tm6000_ir_fini(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       /* skip detach on non attached board */
+
+       if (!ir)
+               return 0;
+
+       ir_input_unregister(ir->input->input_dev);
+
+       if (ir->int_urb) {
+               usb_kill_urb(ir->int_urb);
+               kfree(ir->int_urb->transfer_buffer);
+               usb_free_urb(ir->int_urb);
+               ir->int_urb = NULL;
+               kfree(ir->urb_data);
+               ir->urb_data = NULL;
+       }
+
+       kfree(ir->input);
+       ir->input = NULL;
+       kfree(ir);
+       dev->ir = NULL;
+
+       return 0;
+}
index b3564f611e5e6522ca2bd148cbf601e5dbf913d1..6bf4a73b320d82327d9fd7a64487a7212f853e7a 100644 (file)
@@ -77,7 +77,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -135,7 +135,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -193,7 +193,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -251,7 +251,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -308,7 +308,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
@@ -354,7 +354,7 @@ static struct tm6000_std_settings composite_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -396,7 +396,7 @@ static struct tm6000_std_settings composite_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -438,7 +438,7 @@ static struct tm6000_std_settings composite_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -480,7 +480,7 @@ static struct tm6000_std_settings composite_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -521,7 +521,7 @@ static struct tm6000_std_settings composite_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
@@ -567,7 +567,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -609,7 +609,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -651,7 +651,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -693,7 +693,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
                        {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -734,7 +734,7 @@ static struct tm6000_std_settings svideo_stds[] = {
                        {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
                        {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
                        {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
-                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+                       {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
                        {TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b},
                        {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
                        {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
@@ -763,11 +763,11 @@ static struct tm6000_std_settings svideo_stds[] = {
 void tm6000_get_std_res(struct tm6000_core *dev)
 {
        /* Currently, those are the only supported resoltions */
-       if (dev->norm & V4L2_STD_525_60) {
+       if (dev->norm & V4L2_STD_525_60)
                dev->height = 480;
-       } else {
+       else
                dev->height = 576;
-       }
+
        dev->width = 720;
 }
 
index 5a5049acd4ec51f988267e2aaf2d205814c8156c..138716a8f056c1f25cde82000f446849520628aa 100644 (file)
@@ -39,7 +39,7 @@ struct usb_isoc_ctl {
        int                             pos, size, pktsize;
 
                /* Last field: ODD or EVEN? */
-       int                             field;
+       int                             vfield;
 
                /* Stores incomplete commands */
        u32                             tmp_buf;
@@ -47,7 +47,4 @@ struct usb_isoc_ctl {
 
                /* Stores already requested buffers */
        struct tm6000_buffer            *buf;
-
-               /* Stores the number of received fields */
-       int                             nfields;
 };
index 56fa371e08c89e21c1b7eed1e3afd6ccad7b8820..ce0a089a07717a5ee5ce24ddeecd0c0789e4a8da 100644 (file)
@@ -56,6 +56,7 @@ static int video_nr = -1;             /* /dev/videoN, -1 for autodetect */
 
 /* Debug level */
 int tm6000_debug;
+EXPORT_SYMBOL_GPL(tm6000_debug);
 
 /* supported controls */
 static struct v4l2_queryctrl tm6000_qctrl[] = {
@@ -149,8 +150,6 @@ static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
 
        /* Cleans up buffer - Usefull for testing for frame/URB loss */
        outp = videobuf_to_vmalloc(&(*buf)->vb);
-//     if (outp)
-//             memset(outp, 0, (*buf)->vb.size);
 
        return;
 }
@@ -186,236 +185,152 @@ const char *tm6000_msg_type[] = {
 /*
  * Identify the tm5600/6000 buffer header type and properly handles
  */
-static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
-                       u8 *out_p, struct tm6000_buffer **buf)
-{
-       struct tm6000_dmaqueue  *dma_q = urb->context;
-       struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-       u8 c;
-       unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
-       int rc = 0;
-       /* FIXME: move to tm6000-isoc */
-       static int last_line = -2, start_line = -2, last_field = -2;
-
-       /* FIXME: this is the hardcoded window size
-        */
-       unsigned int linewidth = (*buf)->vb.width << 1;
-
-       if (!dev->isoc_ctl.cmd) {
-               c = (header >> 24) & 0xff;
-
-               /* split the header fields */
-               size  = ((header & 0x7e) << 1);
-
-               if (size > 0)
-                       size -= 4;
-
-               block = (header >> 7) & 0xf;
-               field = (header >> 11) & 0x1;
-               line  = (header >> 12) & 0x1ff;
-               cmd   = (header >> 21) & 0x7;
-
-               /* Validates header fields */
-               if(size > TM6000_URB_MSG_LEN)
-                       size = TM6000_URB_MSG_LEN;
-
-               if (cmd == TM6000_URB_MSG_VIDEO) {
-                       if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
-                               cmd = TM6000_URB_MSG_ERR;
-
-                       /* FIXME: Mounts the image as field0+field1
-                        * It should, instead, check if the user selected
-                        * entrelaced or non-entrelaced mode
-                        */
-                       pos = ((line << 1) - field - 1) * linewidth +
-                               block * TM6000_URB_MSG_LEN;
-
-                       /* Don't allow to write out of the buffer */
-                       if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
-                               dprintk(dev, V4L2_DEBUG_ISOC,
-                                       "ERR: size=%d, num=%d, line=%d, "
-                                       "field=%d\n",
-                                       size, block, line, field);
-
-                               cmd = TM6000_URB_MSG_ERR;
-                       }
-               } else {
-                       pos=0;
-               }
-
-               /* Prints debug info */
-               dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
-                               " line=%d, field=%d\n",
-                               size, block, line, field);
-
-               if ((last_line!=line)&&(last_line+1!=line) &&
-                   (cmd != TM6000_URB_MSG_ERR) )  {
-                       if (cmd != TM6000_URB_MSG_VIDEO)  {
-                               dprintk(dev, V4L2_DEBUG_ISOC,  "cmd=%d, "
-                                       "size=%d, num=%d, line=%d, field=%d\n",
-                                       cmd, size, block, line, field);
-                       }
-                       if (start_line<0)
-                               start_line=last_line;
-                       /* Prints debug info */
-                       dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
-                                       "field=%d\n",
-                                       start_line, last_line, field);
-
-                       if ((start_line<6 && last_line>200) &&
-                               (last_field != field) ) {
-
-                               dev->isoc_ctl.nfields++;
-                               if (dev->isoc_ctl.nfields>=2) {
-                                       dev->isoc_ctl.nfields=0;
-
-                                       /* Announces that a new buffer were filled */
-                                       buffer_filled (dev, dma_q, *buf);
-                                       dprintk(dev, V4L2_DEBUG_ISOC,
-                                                       "new buffer filled\n");
-                                       get_next_buf (dma_q, buf);
-                                       if (!*buf)
-                                               return rc;
-                                       out_p = videobuf_to_vmalloc(&((*buf)->vb));
-                                       if (!out_p)
-                                               return rc;
-
-                                       pos = dev->isoc_ctl.pos = 0;
-                               }
-                       }
-
-                       start_line=line;
-                       last_field=field;
-               }
-               if (cmd == TM6000_URB_MSG_VIDEO)
-                       last_line = line;
-
-               pktsize = TM6000_URB_MSG_LEN;
-       } else {
-               /* Continue the last copy */
-               cmd = dev->isoc_ctl.cmd;
-               size= dev->isoc_ctl.size;
-               pos = dev->isoc_ctl.pos;
-               pktsize = dev->isoc_ctl.pktsize;
-       }
-
-       cpysize = (endp-(*ptr) > size) ? size : endp - *ptr;
-
-       if (cpysize) {
-               /* handles each different URB message */
-               switch(cmd) {
-               case TM6000_URB_MSG_VIDEO:
-                       /* Fills video buffer */
-                       memcpy(&out_p[pos], *ptr, cpysize);
-                       break;
-               case TM6000_URB_MSG_PTS:
-                       break;
-               case TM6000_URB_MSG_AUDIO:
-                       /* Need some code to process audio */
-                       printk ("%ld: cmd=%s, size=%d\n", jiffies,
-                               tm6000_msg_type[cmd],size);
-                       break;
-               case TM6000_URB_MSG_VBI:
-                       break;
-               default:
-                       dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
-                                               tm6000_msg_type[cmd],size);
-               }
-       }
-       if (cpysize<size) {
-               /* End of URB packet, but cmd processing is not
-                * complete. Preserve the state for a next packet
-                */
-               dev->isoc_ctl.pos = pos+cpysize;
-               dev->isoc_ctl.size= size-cpysize;
-               dev->isoc_ctl.cmd = cmd;
-               dev->isoc_ctl.pktsize = pktsize-cpysize;
-               (*ptr)+=cpysize;
-       } else {
-               dev->isoc_ctl.cmd = 0;
-               (*ptr)+=pktsize;
-       }
-
-       return rc;
-}
-
 static int copy_streams(u8 *data, unsigned long len,
                        struct urb *urb)
 {
        struct tm6000_dmaqueue  *dma_q = urb->context;
        struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
-       u8 *ptr=data, *endp=data+len;
+       u8 *ptr=data, *endp=data+len, c;
        unsigned long header=0;
        int rc=0;
-       struct tm6000_buffer *buf;
-       char *outp = NULL;
-
-       get_next_buf(dma_q, &buf);
-       if (buf)
-               outp = videobuf_to_vmalloc(&buf->vb);
+       unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+       struct tm6000_buffer *vbuf;
+       char *voutp = NULL;
+       unsigned int linewidth;
 
-       if (!outp)
+       /* 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;) {
+       for (ptr = data; ptr < endp;) {
                if (!dev->isoc_ctl.cmd) {
-                       u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
-                       /* FIXME: This seems very complex
-                        * It just recovers up to 3 bytes of the header that
-                        * might be at the previous packet
-                        */
-                       if (dev->isoc_ctl.tmp_buf_len) {
-                               while (dev->isoc_ctl.tmp_buf_len) {
-                                       if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
-                                               break;
-                                       }
-                                       p++;
-                                       dev->isoc_ctl.tmp_buf_len--;
-                               }
-                               if (dev->isoc_ctl.tmp_buf_len) {
-                                       memcpy(&header, p,
-                                               dev->isoc_ctl.tmp_buf_len);
-                                       memcpy((u8 *)&header +
+                       /* Header */
+                       if (dev->isoc_ctl.tmp_buf_len > 0) {
+                               /* from last urb or packet */
+                               header = dev->isoc_ctl.tmp_buf;
+                               if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
+                                       memcpy ((u8 *)&header +
                                                dev->isoc_ctl.tmp_buf_len,
                                                ptr,
                                                4 - dev->isoc_ctl.tmp_buf_len);
                                        ptr += 4 - dev->isoc_ctl.tmp_buf_len;
-                                       goto HEADER;
                                }
-                       }
-                       /* Seek for sync */
-                       for (;ptr<endp-3;ptr++) {
-                               if (*(ptr+3)==0x47)
-                                       break;
+                               dev->isoc_ctl.tmp_buf_len = 0;
+                       } else {
+                               if (ptr + 3 >= endp) {
+                                       /* have incomplete header */
+                                       dev->isoc_ctl.tmp_buf_len = endp - ptr;
+                                       memcpy (&dev->isoc_ctl.tmp_buf, ptr,
+                                               dev->isoc_ctl.tmp_buf_len);
+                                       return rc;
+                               }
+                               /* Seek for sync */
+                               for (; ptr < endp - 3; ptr++) {
+                                       if (*(ptr + 3) == 0x47)
+                                               break;
+                               }
+                               /* Get message header */
+                               header = *(unsigned long *)ptr;
+                               ptr += 4;
                        }
 
-                       if (ptr+3>=endp) {
-                               dev->isoc_ctl.tmp_buf_len=endp-ptr;
-                               memcpy (&dev->isoc_ctl.tmp_buf,ptr,
-                                       dev->isoc_ctl.tmp_buf_len);
-                               dev->isoc_ctl.cmd=0;
-                               return rc;
+                       /* split the header fields */
+                       c = (header >> 24) & 0xff;
+                       size = ((header & 0x7e) << 1);
+                       if (size > 0)
+                               size -= 4;
+                       block = (header >> 7) & 0xf;
+                       field = (header >> 11) & 0x1;
+                       line  = (header >> 12) & 0x1ff;
+                       cmd   = (header >> 21) & 0x7;
+                       /* Validates haeder fields */
+                       if (size > TM6000_URB_MSG_LEN)
+                               size = TM6000_URB_MSG_LEN;
+                       pktsize = TM6000_URB_MSG_LEN;
+                       /* calculate position in buffer
+                        * and change the buffer
+                        */
+                       switch (cmd) {
+                       case TM6000_URB_MSG_VIDEO:
+                               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,
+                                                       "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;
+                               break;
+                       case TM6000_URB_MSG_VBI:
+                               break;
+                       case TM6000_URB_MSG_AUDIO:
+                       case TM6000_URB_MSG_PTS:
+                               size = pktsize;         /* Size is always 180 bytes */
+                               break;
                        }
-
-                       /* Get message header */
-                       header=*(unsigned long *)ptr;
-                       ptr+=4;
+               } else {
+                       /* Continue the last copy */
+                       cmd = dev->isoc_ctl.cmd;
+                       size = dev->isoc_ctl.size;
+                       pos = dev->isoc_ctl.pos;
+                       pktsize = dev->isoc_ctl.pktsize;
                }
-HEADER:
-               /* Copy or continue last copy */
-               rc=copy_packet(urb,header,&ptr,endp,outp,&buf);
-               if (rc<0) {
-                       buf=NULL;
-                       printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
-                                       jiffies);
-                       return rc;
+               cpysize = (endp - ptr > size) ? size : endp - ptr;
+               if (cpysize) {
+                       /* copy data in different buffers */
+                       switch (cmd) {
+                       case TM6000_URB_MSG_VIDEO:
+                               /* Fills video buffer */
+                               if (vbuf)
+                                       memcpy (&voutp[pos], ptr, cpysize);
+                               break;
+                       case TM6000_URB_MSG_AUDIO:
+                               tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
+                               break;
+                       case TM6000_URB_MSG_VBI:
+                               /* Need some code to copy vbi buffer */
+                               break;
+                       case TM6000_URB_MSG_PTS:
+                               /* Need some code to copy pts */
+                               break;
+                       }
+               }
+               if (ptr + pktsize > endp) {
+                       /* End of URB packet, but cmd processing is not
+                        * complete. Preserve the state for a next packet
+                        */
+                       dev->isoc_ctl.pos = pos + cpysize;
+                       dev->isoc_ctl.size = size - cpysize;
+                       dev->isoc_ctl.cmd = cmd;
+                       dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
+                       ptr += endp - ptr;
+               } else {
+                       dev->isoc_ctl.cmd = 0;
+                       ptr += pktsize;
                }
-               if (!buf)
-                       return 0;
        }
-
        return 0;
 }
+
 /*
  * Identify the tm5600/6000 buffer header type and properly handles
  */
@@ -510,7 +425,6 @@ static inline int tm6000_isoc_copy(struct urb *urb)
 {
        struct tm6000_dmaqueue  *dma_q = urb->context;
        struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
-       struct tm6000_buffer *buf;
        int i, len=0, rc=1, status;
        char *p;
 
@@ -585,7 +499,6 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
        struct urb *urb;
        int i;
 
-       dev->isoc_ctl.nfields = -1;
        dev->isoc_ctl.buf = NULL;
        for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
                urb=dev->isoc_ctl.urb[i];
@@ -610,8 +523,6 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
        dev->isoc_ctl.urb=NULL;
        dev->isoc_ctl.transfer_buffer=NULL;
        dev->isoc_ctl.num_bufs = 0;
-
-       dev->isoc_ctl.num_bufs=0;
 }
 
 /*
index 7bbaf26dea14f292b1808820698a702981514ebe..1ec1bff9b294b76e90af2f0d73890351da524bc2 100644 (file)
@@ -20,8 +20,8 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-// Use the tm6000-hack, instead of the proper initialization code
-//#define HACK 1
+/* Use the tm6000-hack, instead of the proper initialization code i*/
+/* #define HACK 1 */
 
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
@@ -98,7 +98,7 @@ enum tm6000_io_method {
 };
 
 enum tm6000_mode {
-       TM6000_MODE_UNKNOWN=0,
+       TM6000_MODE_UNKNOWN = 0,
        TM6000_MODE_ANALOG,
        TM6000_MODE_DIGITAL,
 };
@@ -128,10 +128,21 @@ struct tm6000_dvb {
        struct dvb_frontend     *frontend;
        struct dmxdev           dmxdev;
        unsigned int            streams;
-       struct urb              *bulk_urb;
+       struct urb              *bulk_urb;
        struct mutex            mutex;
 };
 
+struct snd_tm6000_card {
+       struct snd_card                 *card;
+       spinlock_t                      reg_lock;
+       struct tm6000_core              *core;
+       struct snd_pcm_substream        *substream;
+
+       /* temporary data for buffer fill processing */
+       unsigned                        buf_pos;
+       unsigned                        period_pos;
+};
+
 struct tm6000_endpoint {
        struct usb_host_endpoint        *endp;
        __u8                            bInterfaceNumber;
@@ -147,7 +158,7 @@ struct tm6000_core {
        enum tm6000_devtype             dev_type;       /* type of device */
 
        v4l2_std_id                     norm;           /* Current norm */
-       int                             width,height;   /* Selected resolution */
+       int                             width, height;  /* Selected resolution */
 
        enum tm6000_core_state          state;
 
@@ -160,6 +171,8 @@ struct tm6000_core {
 
        struct tm6000_gpio              gpio;
 
+       char                            *ir_codes;
+
        /* Demodulator configuration */
        int                             demod_addr;     /* demodulator address */
 
@@ -190,6 +203,11 @@ struct tm6000_core {
        /* DVB-T support */
        struct tm6000_dvb               *dvb;
 
+       /* audio support */
+       struct snd_tm6000_card          *adev;
+
+       struct tm6000_IR                *ir;
+
        /* locks */
        struct mutex                    lock;
 
@@ -197,6 +215,7 @@ struct tm6000_core {
        struct usb_device               *udev;          /* the usb device */
 
        struct tm6000_endpoint          bulk_in, bulk_out, isoc_in, isoc_out;
+       struct tm6000_endpoint          int_in, int_out;
 
        /* scaler!=0 if scaler is active*/
        int                             scaler;
@@ -207,14 +226,18 @@ struct tm6000_core {
        spinlock_t                   slock;
 };
 
-#define TM6000_AUDIO 0x10
+enum tm6000_ops_type {
+       TM6000_AUDIO = 0x10,
+       TM6000_DVB = 0x20,
+};
 
 struct tm6000_ops {
        struct list_head        next;
        char                    *name;
-       int                     id;
+       enum tm6000_ops_type    type;
        int (*init)(struct tm6000_core *);
        int (*fini)(struct tm6000_core *);
+       int (*fillbuf)(struct tm6000_core *, char *buf, int size);
 };
 
 struct tm6000_fh {
@@ -222,7 +245,7 @@ struct tm6000_fh {
 
        /* video capture */
        struct tm6000_fmt            *fmt;
-       unsigned int                 width,height;
+       unsigned int                 width, height;
        struct videobuf_queue        vb_vidq;
 
        enum v4l2_buf_type           type;
@@ -234,28 +257,24 @@ struct tm6000_fh {
 
 /* In tm6000-cards.c */
 
-int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
-int tm6000_xc5000_callback (void *ptr, int component, int command, int arg);
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
+int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
 int tm6000_cards_setup(struct tm6000_core *dev);
 
 /* In tm6000-core.c */
 
-int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
                           u16 value, u16 index, u8 *buf, u16 len);
-int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+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(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
+int tm6000_init(struct tm6000_core *dev);
 
-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_dvb_register(struct tm6000_core *dev);
-void tm6000_dvb_unregister(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_v4l2_register(struct tm6000_core *dev);
 int tm6000_v4l2_unregister(struct tm6000_core *dev);
@@ -268,10 +287,13 @@ int tm6000_register_extension(struct tm6000_ops *ops);
 void tm6000_unregister_extension(struct tm6000_ops *ops);
 void tm6000_init_extension(struct tm6000_core *dev);
 void tm6000_close_extension(struct tm6000_core *dev);
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+                       char *buf, int size);
+
 
 /* In tm6000-stds.c */
 void tm6000_get_std_res(struct tm6000_core *dev);
-int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
+int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id *norm);
 
 /* In tm6000-i2c.c */
 int tm6000_i2c_register(struct tm6000_core *dev);
@@ -285,14 +307,14 @@ int tm6000_vidioc_streamon(struct file *file, void *priv,
                           enum v4l2_buf_type i);
 int tm6000_vidioc_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type i);
-int tm6000_vidioc_reqbufs (struct file *file, void *priv,
-                          struct v4l2_requestbuffers *rb);
-int tm6000_vidioc_querybuf (struct file *file, void *priv,
-                           struct v4l2_buffer *b);
-int tm6000_vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *b);
-int tm6000_vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *rb);
+int tm6000_vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *b);
+int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
 ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
-                        loff_t * f_pos);
+                        loff_t *f_pos);
 unsigned int tm6000_v4l2_poll(struct file *file,
                              struct poll_table_struct *wait);
 int tm6000_queue_init(struct tm6000_core *dev);
@@ -300,6 +322,10 @@ int tm6000_queue_init(struct tm6000_core *dev);
 /* In tm6000-alsa.c */
 /*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
 
+/* In tm6000-input.c */
+int tm6000_ir_init(struct tm6000_core *dev);
+int tm6000_ir_fini(struct tm6000_core *dev);
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
 
 /* Debug stuff */
 
@@ -307,7 +333,7 @@ extern int tm6000_debug;
 
 #define dprintk(dev, level, fmt, arg...) do {\
        if (tm6000_debug & level) \
-               printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies,           \
+               printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
                         dev->name, __FUNCTION__ , ##arg); } while (0)
 
 #define V4L2_DEBUG_REG         0x0004
@@ -320,5 +346,3 @@ extern int tm6000_debug;
 #define tm6000_err(fmt, arg...) do {\
        printk(KERN_ERR "tm6000 %s :"fmt, \
                __FUNCTION__ , ##arg); } while (0)
-
-
index eaa79c8a9b8c2bee44fdce43f2963d19087213a3..93ead19507b632c20095980fd5b0350d6407d23d 100644 (file)
 static const char driver_name [] = "at91_udc";
 static const char ep0name[] = "ep0";
 
+#define VBUS_POLL_TIMEOUT      msecs_to_jiffies(1000)
 
-#define at91_udp_read(dev, reg) \
-       __raw_readl((dev)->udp_baseaddr + (reg))
-#define at91_udp_write(dev, reg, val) \
-       __raw_writel((val), (dev)->udp_baseaddr + (reg))
+#define at91_udp_read(udc, reg) \
+       __raw_readl((udc)->udp_baseaddr + (reg))
+#define at91_udp_write(udc, reg, val) \
+       __raw_writel((val), (udc)->udp_baseaddr + (reg))
 
 /*-------------------------------------------------------------------------*/
 
@@ -102,8 +103,9 @@ static void proc_ep_show(struct seq_file *s, struct at91_ep *ep)
        u32                     csr;
        struct at91_request     *req;
        unsigned long   flags;
+       struct at91_udc *udc = ep->udc;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
 
        csr = __raw_readl(ep->creg);
 
@@ -147,7 +149,7 @@ static void proc_ep_show(struct seq_file *s, struct at91_ep *ep)
                                &req->req, length,
                                req->req.length, req->req.buf);
        }
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
 }
 
 static void proc_irq_show(struct seq_file *s, const char *label, u32 mask)
@@ -272,7 +274,9 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status)
                VDBG("%s done %p, status %d\n", ep->ep.name, req, status);
 
        ep->stopped = 1;
+       spin_unlock(&udc->lock);
        req->req.complete(&ep->ep, &req->req);
+       spin_lock(&udc->lock);
        ep->stopped = stopped;
 
        /* ep0 is always ready; other endpoints need a non-empty queue */
@@ -472,7 +476,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
                                const struct usb_endpoint_descriptor *desc)
 {
        struct at91_ep  *ep = container_of(_ep, struct at91_ep, ep);
-       struct at91_udc *dev = ep->udc;
+       struct at91_udc *udc = ep->udc;
        u16             maxpacket;
        u32             tmp;
        unsigned long   flags;
@@ -487,7 +491,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
                return -EINVAL;
        }
 
-       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
                DBG("bogus device state\n");
                return -ESHUTDOWN;
        }
@@ -521,7 +525,7 @@ bogus_max:
        }
 
 ok:
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
 
        /* initialize endpoint to match this descriptor */
        ep->is_in = usb_endpoint_dir_in(desc);
@@ -540,10 +544,10 @@ ok:
         * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
         * since endpoint resets don't reset hw pingpong state.
         */
-       at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);
-       at91_udp_write(dev, AT91_UDP_RST_EP, 0);
+       at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+       at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
 
@@ -556,7 +560,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
        if (ep == &ep->udc->ep[0])
                return -EINVAL;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
 
        nuke(ep, -ESHUTDOWN);
 
@@ -571,7 +575,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
                __raw_writel(0, ep->creg);
        }
 
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
 
@@ -607,7 +611,7 @@ static int at91_ep_queue(struct usb_ep *_ep,
 {
        struct at91_request     *req;
        struct at91_ep          *ep;
-       struct at91_udc         *dev;
+       struct at91_udc         *udc;
        int                     status;
        unsigned long           flags;
 
@@ -625,9 +629,9 @@ static int at91_ep_queue(struct usb_ep *_ep,
                return -EINVAL;
        }
 
-       dev = ep->udc;
+       udc = ep->udc;
 
-       if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+       if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
                DBG("invalid device\n");
                return -EINVAL;
        }
@@ -635,7 +639,7 @@ static int at91_ep_queue(struct usb_ep *_ep,
        _req->status = -EINPROGRESS;
        _req->actual = 0;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
 
        /* try to kickstart any empty and idle queue */
        if (list_empty(&ep->queue) && !ep->stopped) {
@@ -653,7 +657,7 @@ static int at91_ep_queue(struct usb_ep *_ep,
                if (is_ep0) {
                        u32     tmp;
 
-                       if (!dev->req_pending) {
+                       if (!udc->req_pending) {
                                status = -EINVAL;
                                goto done;
                        }
@@ -662,11 +666,11 @@ static int at91_ep_queue(struct usb_ep *_ep,
                         * defer changing CONFG until after the gadget driver
                         * reconfigures the endpoints.
                         */
-                       if (dev->wait_for_config_ack) {
-                               tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT);
+                       if (udc->wait_for_config_ack) {
+                               tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
                                tmp ^= AT91_UDP_CONFG;
                                VDBG("toggle config\n");
-                               at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp);
+                               at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
                        }
                        if (req->req.length == 0) {
 ep0_in_status:
@@ -676,7 +680,7 @@ ep0_in_status:
                                tmp &= ~SET_FX;
                                tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
                                __raw_writel(tmp, ep->creg);
-                               dev->req_pending = 0;
+                               udc->req_pending = 0;
                                goto done;
                        }
                }
@@ -695,31 +699,40 @@ ep0_in_status:
 
        if (req && !status) {
                list_add_tail (&req->queue, &ep->queue);
-               at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);
+               at91_udp_write(udc, AT91_UDP_IER, ep->int_mask);
        }
 done:
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return (status < 0) ? status : 0;
 }
 
 static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 {
-       struct at91_ep  *ep;
+       struct at91_ep          *ep;
        struct at91_request     *req;
+       unsigned long           flags;
+       struct at91_udc         *udc;
 
        ep = container_of(_ep, struct at91_ep, ep);
        if (!_ep || ep->ep.name == ep0name)
                return -EINVAL;
 
+       udc = ep->udc;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
        /* make sure it's actually queued on this endpoint */
        list_for_each_entry (req, &ep->queue, queue) {
                if (&req->req == _req)
                        break;
        }
-       if (&req->req != _req)
+       if (&req->req != _req) {
+               spin_unlock_irqrestore(&udc->lock, flags);
                return -EINVAL;
+       }
 
        done(ep, req, -ECONNRESET);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
 
@@ -736,7 +749,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value)
                return -EINVAL;
 
        creg = ep->creg;
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
 
        csr = __raw_readl(creg);
 
@@ -761,7 +774,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value)
                __raw_writel(csr, creg);
        }
 
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return status;
 }
 
@@ -795,7 +808,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
        unsigned long   flags;
 
        DBG("%s\n", __func__ );
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
 
        if (!udc->clocked || !udc->suspended)
                goto done;
@@ -809,7 +822,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
        at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
 
 done:
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return status;
 }
 
@@ -851,8 +864,11 @@ static void stop_activity(struct at91_udc *udc)
                ep->stopped = 1;
                nuke(ep, -ESHUTDOWN);
        }
-       if (driver)
+       if (driver) {
+               spin_unlock(&udc->lock);
                driver->disconnect(&udc->gadget);
+               spin_lock(&udc->lock);
+       }
 
        udc_reinit(udc);
 }
@@ -935,13 +951,13 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
        unsigned long   flags;
 
        // VDBG("vbus %s\n", is_active ? "on" : "off");
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
        udc->vbus = (is_active != 0);
        if (udc->driver)
                pullup(udc, is_active);
        else
                pullup(udc, 0);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
 
@@ -950,10 +966,10 @@ static int at91_pullup(struct usb_gadget *gadget, int is_on)
        struct at91_udc *udc = to_udc(gadget);
        unsigned long   flags;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
        udc->enabled = is_on = !!is_on;
        pullup(udc, is_on);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
 
@@ -962,9 +978,9 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
        struct at91_udc *udc = to_udc(gadget);
        unsigned long   flags;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&udc->lock, flags);
        udc->selfpowered = (is_on != 0);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
 
@@ -1226,8 +1242,11 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
 #undef w_length
 
        /* pass request up to the gadget driver */
-       if (udc->driver)
+       if (udc->driver) {
+               spin_unlock(&udc->lock);
                status = udc->driver->setup(&udc->gadget, &pkt.r);
+               spin_lock(&udc->lock);
+       }
        else
                status = -ENODEV;
        if (status < 0) {
@@ -1378,6 +1397,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
        struct at91_udc         *udc = _udc;
        u32                     rescans = 5;
        int                     disable_clock = 0;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
 
        if (!udc->clocked) {
                clk_on(udc);
@@ -1433,8 +1455,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
                         * and then into standby to avoid drawing more than
                         * 500uA power (2500uA for some high-power configs).
                         */
-                       if (udc->driver && udc->driver->suspend)
+                       if (udc->driver && udc->driver->suspend) {
+                               spin_unlock(&udc->lock);
                                udc->driver->suspend(&udc->gadget);
+                               spin_lock(&udc->lock);
+                       }
 
                /* host initiated resume */
                } else if (status & AT91_UDP_RXRSM) {
@@ -1451,8 +1476,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
                         * would normally want to switch out of slow clock
                         * mode into normal mode.
                         */
-                       if (udc->driver && udc->driver->resume)
+                       if (udc->driver && udc->driver->resume) {
+                               spin_unlock(&udc->lock);
                                udc->driver->resume(&udc->gadget);
+                               spin_lock(&udc->lock);
+                       }
 
                /* endpoint IRQs are cleared by handling them */
                } else {
@@ -1474,6 +1502,8 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
        if (disable_clock)
                clk_off(udc);
 
+       spin_unlock_irqrestore(&udc->lock, flags);
+
        return IRQ_HANDLED;
 }
 
@@ -1556,24 +1586,53 @@ static struct at91_udc controller = {
        /* ep6 and ep7 are also reserved (custom silicon might use them) */
 };
 
+static void at91_vbus_update(struct at91_udc *udc, unsigned value)
+{
+       value ^= udc->board.vbus_active_low;
+       if (value != udc->vbus)
+               at91_vbus_session(&udc->gadget, value);
+}
+
 static irqreturn_t at91_vbus_irq(int irq, void *_udc)
 {
        struct at91_udc *udc = _udc;
-       unsigned        value;
 
        /* vbus needs at least brief debouncing */
        udelay(10);
-       value = gpio_get_value(udc->board.vbus_pin);
-       if (value != udc->vbus)
-               at91_vbus_session(&udc->gadget, value);
+       at91_vbus_update(udc, gpio_get_value(udc->board.vbus_pin));
 
        return IRQ_HANDLED;
 }
 
+static void at91_vbus_timer_work(struct work_struct *work)
+{
+       struct at91_udc *udc = container_of(work, struct at91_udc,
+                                           vbus_timer_work);
+
+       at91_vbus_update(udc, gpio_get_value_cansleep(udc->board.vbus_pin));
+
+       if (!timer_pending(&udc->vbus_timer))
+               mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT);
+}
+
+static void at91_vbus_timer(unsigned long data)
+{
+       struct at91_udc *udc = (struct at91_udc *)data;
+
+       /*
+        * If we are polling vbus it is likely that the gpio is on an
+        * bus such as i2c or spi which may sleep, so schedule some work
+        * to read the vbus gpio
+        */
+       if (!work_pending(&udc->vbus_timer_work))
+               schedule_work(&udc->vbus_timer_work);
+}
+
 int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 {
        struct at91_udc *udc = &controller;
        int             retval;
+       unsigned long   flags;
 
        if (!driver
                        || driver->speed < USB_SPEED_FULL
@@ -1605,9 +1664,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                return retval;
        }
 
-       local_irq_disable();
+       spin_lock_irqsave(&udc->lock, flags);
        pullup(udc, 1);
-       local_irq_enable();
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        DBG("bound to %s\n", driver->driver.name);
        return 0;
@@ -1617,15 +1676,16 @@ EXPORT_SYMBOL (usb_gadget_register_driver);
 int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
        struct at91_udc *udc = &controller;
+       unsigned long   flags;
 
        if (!driver || driver != udc->driver || !driver->unbind)
                return -EINVAL;
 
-       local_irq_disable();
+       spin_lock_irqsave(&udc->lock, flags);
        udc->enabled = 0;
        at91_udp_write(udc, AT91_UDP_IDR, ~0);
        pullup(udc, 0);
-       local_irq_enable();
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        driver->unbind(&udc->gadget);
        udc->gadget.dev.driver = NULL;
@@ -1641,8 +1701,13 @@ EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 static void at91udc_shutdown(struct platform_device *dev)
 {
+       struct at91_udc *udc = platform_get_drvdata(dev);
+       unsigned long   flags;
+
        /* force disconnect on reboot */
+       spin_lock_irqsave(&udc->lock, flags);
        pullup(platform_get_drvdata(dev), 0);
+       spin_unlock_irqrestore(&udc->lock, flags);
 }
 
 static int __init at91udc_probe(struct platform_device *pdev)
@@ -1683,6 +1748,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
        udc->board = *(struct at91_udc_data *) dev->platform_data;
        udc->pdev = pdev;
        udc->enabled = 0;
+       spin_lock_init(&udc->lock);
 
        /* rm9200 needs manual D+ pullup; off by default */
        if (cpu_is_at91rm9200()) {
@@ -1763,13 +1829,23 @@ static int __init at91udc_probe(struct platform_device *pdev)
                 * Get the initial state of VBUS - we cannot expect
                 * a pending interrupt.
                 */
-               udc->vbus = gpio_get_value(udc->board.vbus_pin);
-               if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
-                               IRQF_DISABLED, driver_name, udc)) {
-                       DBG("request vbus irq %d failed\n",
-                                       udc->board.vbus_pin);
-                       retval = -EBUSY;
-                       goto fail3;
+               udc->vbus = gpio_get_value_cansleep(udc->board.vbus_pin) ^
+                       udc->board.vbus_active_low;
+
+               if (udc->board.vbus_polled) {
+                       INIT_WORK(&udc->vbus_timer_work, at91_vbus_timer_work);
+                       setup_timer(&udc->vbus_timer, at91_vbus_timer,
+                                   (unsigned long)udc);
+                       mod_timer(&udc->vbus_timer,
+                                 jiffies + VBUS_POLL_TIMEOUT);
+               } else {
+                       if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
+                                       IRQF_DISABLED, driver_name, udc)) {
+                               DBG("request vbus irq %d failed\n",
+                                   udc->board.vbus_pin);
+                               retval = -EBUSY;
+                               goto fail3;
+                       }
                }
        } else {
                DBG("no VBUS detection, assuming always-on\n");
@@ -1804,13 +1880,16 @@ static int __exit at91udc_remove(struct platform_device *pdev)
 {
        struct at91_udc *udc = platform_get_drvdata(pdev);
        struct resource *res;
+       unsigned long   flags;
 
        DBG("remove\n");
 
        if (udc->driver)
                return -EBUSY;
 
+       spin_lock_irqsave(&udc->lock, flags);
        pullup(udc, 0);
+       spin_unlock_irqrestore(&udc->lock, flags);
 
        device_init_wakeup(&pdev->dev, 0);
        remove_debug_file(udc);
@@ -1840,6 +1919,7 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
        struct at91_udc *udc = platform_get_drvdata(pdev);
        int             wake = udc->driver && device_may_wakeup(&pdev->dev);
+       unsigned long   flags;
 
        /* Unless we can act normally to the host (letting it wake us up
         * whenever it has work for us) force disconnect.  Wakeup requires
@@ -1849,13 +1929,15 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
        if ((!udc->suspended && udc->addr)
                        || !wake
                        || at91_suspend_entering_slow_clock()) {
+               spin_lock_irqsave(&udc->lock, flags);
                pullup(udc, 0);
                wake = 0;
+               spin_unlock_irqrestore(&udc->lock, flags);
        } else
                enable_irq_wake(udc->udp_irq);
 
        udc->active_suspend = wake;
-       if (udc->board.vbus_pin > 0 && wake)
+       if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && wake)
                enable_irq_wake(udc->board.vbus_pin);
        return 0;
 }
@@ -1863,15 +1945,20 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
 static int at91udc_resume(struct platform_device *pdev)
 {
        struct at91_udc *udc = platform_get_drvdata(pdev);
+       unsigned long   flags;
 
-       if (udc->board.vbus_pin > 0 && udc->active_suspend)
+       if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled &&
+           udc->active_suspend)
                disable_irq_wake(udc->board.vbus_pin);
 
        /* maybe reconnect to host; if so, clocks on */
        if (udc->active_suspend)
                disable_irq_wake(udc->udp_irq);
-       else
+       else {
+               spin_lock_irqsave(&udc->lock, flags);
                pullup(udc, 1);
+               spin_unlock_irqrestore(&udc->lock, flags);
+       }
        return 0;
 }
 #else
index c65d62295890e94584045ab9f0cc4b872ab29711..108ca54f9092ff4d01679292cd5acf0d221e81a1 100644 (file)
@@ -144,6 +144,9 @@ struct at91_udc {
        struct proc_dir_entry           *pde;
        void __iomem                    *udp_baseaddr;
        int                             udp_irq;
+       spinlock_t                      lock;
+       struct timer_list               vbus_timer;
+       struct work_struct              vbus_timer_work;
 };
 
 static inline struct at91_udc *to_udc(struct usb_gadget *g)
index dbe6db0184fd043eb3e4bb8a10499c34fea96afa..be446b7e7eaa263d2543552c74ee4e1210591111 100644 (file)
@@ -61,12 +61,12 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
 #define UVC_INTF_VIDEO_STREAMING               1
 
 static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
-       .bLength                = USB_DT_INTERFACE_ASSOCIATION_SIZE,
+       .bLength                = sizeof(uvc_iad),
        .bDescriptorType        = USB_DT_INTERFACE_ASSOCIATION,
        .bFirstInterface        = 0,
        .bInterfaceCount        = 2,
        .bFunctionClass         = USB_CLASS_VIDEO,
-       .bFunctionSubClass      = 0x03,
+       .bFunctionSubClass      = UVC_SC_VIDEO_INTERFACE_COLLECTION,
        .bFunctionProtocol      = 0x00,
        .iFunction              = 0,
 };
@@ -78,7 +78,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
        .bAlternateSetting      = 0,
        .bNumEndpoints          = 1,
        .bInterfaceClass        = USB_CLASS_VIDEO,
-       .bInterfaceSubClass     = 0x01,
+       .bInterfaceSubClass     = UVC_SC_VIDEOCONTROL,
        .bInterfaceProtocol     = 0x00,
        .iInterface             = 0,
 };
@@ -106,7 +106,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
        .bAlternateSetting      = 0,
        .bNumEndpoints          = 0,
        .bInterfaceClass        = USB_CLASS_VIDEO,
-       .bInterfaceSubClass     = 0x02,
+       .bInterfaceSubClass     = UVC_SC_VIDEOSTREAMING,
        .bInterfaceProtocol     = 0x00,
        .iInterface             = 0,
 };
@@ -118,7 +118,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
        .bAlternateSetting      = 1,
        .bNumEndpoints          = 1,
        .bInterfaceClass        = USB_CLASS_VIDEO,
-       .bInterfaceSubClass     = 0x02,
+       .bInterfaceSubClass     = UVC_SC_VIDEOSTREAMING,
        .bInterfaceProtocol     = 0x00,
        .iInterface             = 0,
 };
@@ -603,15 +603,15 @@ uvc_bind_config(struct usb_configuration *c,
 
        /* Validate the descriptors. */
        if (control == NULL || control[0] == NULL ||
-           control[0]->bDescriptorSubType != UVC_DT_HEADER)
+           control[0]->bDescriptorSubType != UVC_VC_HEADER)
                goto error;
 
        if (fs_streaming == NULL || fs_streaming[0] == NULL ||
-           fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+           fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
                goto error;
 
        if (hs_streaming == NULL || hs_streaming[0] == NULL ||
-           hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+           hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
                goto error;
 
        uvc->desc.control = control;
index 8a5db7c4fe7c9de3ab7770c6dc895ef7f0134fbf..e18a6636c283eb51a3f269325b5fe0b3dfc78d7c 100644 (file)
 #define _F_UVC_H_
 
 #include <linux/usb/composite.h>
-
-#define USB_CLASS_VIDEO_CONTROL                1
-#define USB_CLASS_VIDEO_STREAMING      2
-
-struct uvc_descriptor_header {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-} __attribute__ ((packed));
-
-struct uvc_header_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u16 bcdUVC;
-       __u16 wTotalLength;
-       __u32 dwClockFrequency;
-       __u8  bInCollection;
-       __u8  baInterfaceNr[];
-} __attribute__((__packed__));
-
-#define UVC_HEADER_DESCRIPTOR(n)       uvc_header_descriptor_##n
-
-#define DECLARE_UVC_HEADER_DESCRIPTOR(n)                       \
-struct UVC_HEADER_DESCRIPTOR(n) {                              \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u16 bcdUVC;                                           \
-       __u16 wTotalLength;                                     \
-       __u32 dwClockFrequency;                                 \
-       __u8  bInCollection;                                    \
-       __u8  baInterfaceNr[n];                                 \
-} __attribute__ ((packed))
-
-struct uvc_input_terminal_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bTerminalID;
-       __u16 wTerminalType;
-       __u8  bAssocTerminal;
-       __u8  iTerminal;
-} __attribute__((__packed__));
-
-struct uvc_output_terminal_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bTerminalID;
-       __u16 wTerminalType;
-       __u8  bAssocTerminal;
-       __u8  bSourceID;
-       __u8  iTerminal;
-} __attribute__((__packed__));
-
-struct uvc_camera_terminal_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bTerminalID;
-       __u16 wTerminalType;
-       __u8  bAssocTerminal;
-       __u8  iTerminal;
-       __u16 wObjectiveFocalLengthMin;
-       __u16 wObjectiveFocalLengthMax;
-       __u16 wOcularFocalLength;
-       __u8  bControlSize;
-       __u8  bmControls[3];
-} __attribute__((__packed__));
-
-struct uvc_selector_unit_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bUnitID;
-       __u8  bNrInPins;
-       __u8  baSourceID[0];
-       __u8  iSelector;
-} __attribute__((__packed__));
-
-#define UVC_SELECTOR_UNIT_DESCRIPTOR(n)        \
-       uvc_selector_unit_descriptor_##n
-
-#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n)                \
-struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) {                       \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u8  bUnitID;                                          \
-       __u8  bNrInPins;                                        \
-       __u8  baSourceID[n];                                    \
-       __u8  iSelector;                                        \
-} __attribute__ ((packed))
-
-struct uvc_processing_unit_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bUnitID;
-       __u8  bSourceID;
-       __u16 wMaxMultiplier;
-       __u8  bControlSize;
-       __u8  bmControls[2];
-       __u8  iProcessing;
-} __attribute__((__packed__));
-
-struct uvc_extension_unit_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bUnitID;
-       __u8  guidExtensionCode[16];
-       __u8  bNumControls;
-       __u8  bNrInPins;
-       __u8  baSourceID[0];
-       __u8  bControlSize;
-       __u8  bmControls[0];
-       __u8  iExtension;
-} __attribute__((__packed__));
-
-#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
-       uvc_extension_unit_descriptor_##p_##n
-
-#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n)            \
-struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) {                   \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u8  bUnitID;                                          \
-       __u8  guidExtensionCode[16];                            \
-       __u8  bNumControls;                                     \
-       __u8  bNrInPins;                                        \
-       __u8  baSourceID[p];                                    \
-       __u8  bControlSize;                                     \
-       __u8  bmControls[n];                                    \
-       __u8  iExtension;                                       \
-} __attribute__ ((packed))
-
-struct uvc_control_endpoint_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u16 wMaxTransferSize;
-} __attribute__((__packed__));
-
-#define UVC_DT_HEADER                          1
-#define UVC_DT_INPUT_TERMINAL                  2
-#define UVC_DT_OUTPUT_TERMINAL                 3
-#define UVC_DT_SELECTOR_UNIT                   4
-#define UVC_DT_PROCESSING_UNIT                 5
-#define UVC_DT_EXTENSION_UNIT                  6
-
-#define UVC_DT_HEADER_SIZE(n)                  (12+(n))
-#define UVC_DT_INPUT_TERMINAL_SIZE             8
-#define UVC_DT_OUTPUT_TERMINAL_SIZE            9
-#define UVC_DT_CAMERA_TERMINAL_SIZE(n)         (15+(n))
-#define UVC_DT_SELECTOR_UNIT_SIZE(n)           (6+(n))
-#define UVC_DT_PROCESSING_UNIT_SIZE(n)         (9+(n))
-#define UVC_DT_EXTENSION_UNIT_SIZE(p,n)                (24+(p)+(n))
-#define UVC_DT_CONTROL_ENDPOINT_SIZE           5
-
-struct uvc_input_header_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bNumFormats;
-       __u16 wTotalLength;
-       __u8  bEndpointAddress;
-       __u8  bmInfo;
-       __u8  bTerminalLink;
-       __u8  bStillCaptureMethod;
-       __u8  bTriggerSupport;
-       __u8  bTriggerUsage;
-       __u8  bControlSize;
-       __u8  bmaControls[];
-} __attribute__((__packed__));
-
-#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
-       uvc_input_header_descriptor_##n_##p
-
-#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p)              \
-struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) {                     \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u8  bNumFormats;                                      \
-       __u16 wTotalLength;                                     \
-       __u8  bEndpointAddress;                                 \
-       __u8  bmInfo;                                           \
-       __u8  bTerminalLink;                                    \
-       __u8  bStillCaptureMethod;                              \
-       __u8  bTriggerSupport;                                  \
-       __u8  bTriggerUsage;                                    \
-       __u8  bControlSize;                                     \
-       __u8  bmaControls[p][n];                                \
-} __attribute__ ((packed))
-
-struct uvc_output_header_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bNumFormats;
-       __u16 wTotalLength;
-       __u8  bEndpointAddress;
-       __u8  bTerminalLink;
-       __u8  bControlSize;
-       __u8  bmaControls[];
-} __attribute__((__packed__));
-
-#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
-       uvc_output_header_descriptor_##n_##p
-
-#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p)             \
-struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) {                    \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u8  bNumFormats;                                      \
-       __u16 wTotalLength;                                     \
-       __u8  bEndpointAddress;                                 \
-       __u8  bTerminalLink;                                    \
-       __u8  bControlSize;                                     \
-       __u8  bmaControls[p][n];                                \
-} __attribute__ ((packed))
-
-struct uvc_format_uncompressed {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bFormatIndex;
-       __u8  bNumFrameDescriptors;
-       __u8  guidFormat[16];
-       __u8  bBitsPerPixel;
-       __u8  bDefaultFrameIndex;
-       __u8  bAspectRatioX;
-       __u8  bAspectRatioY;
-       __u8  bmInterfaceFlags;
-       __u8  bCopyProtect;
-} __attribute__((__packed__));
-
-struct uvc_frame_uncompressed {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bFrameIndex;
-       __u8  bmCapabilities;
-       __u16 wWidth;
-       __u16 wHeight;
-       __u32 dwMinBitRate;
-       __u32 dwMaxBitRate;
-       __u32 dwMaxVideoFrameBufferSize;
-       __u32 dwDefaultFrameInterval;
-       __u8  bFrameIntervalType;
-       __u32 dwFrameInterval[];
-} __attribute__((__packed__));
-
-#define UVC_FRAME_UNCOMPRESSED(n) \
-       uvc_frame_uncompressed_##n
-
-#define DECLARE_UVC_FRAME_UNCOMPRESSED(n)                      \
-struct UVC_FRAME_UNCOMPRESSED(n) {                             \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u8  bFrameIndex;                                      \
-       __u8  bmCapabilities;                                   \
-       __u16 wWidth;                                           \
-       __u16 wHeight;                                          \
-       __u32 dwMinBitRate;                                     \
-       __u32 dwMaxBitRate;                                     \
-       __u32 dwMaxVideoFrameBufferSize;                        \
-       __u32 dwDefaultFrameInterval;                           \
-       __u8  bFrameIntervalType;                               \
-       __u32 dwFrameInterval[n];                               \
-} __attribute__ ((packed))
-
-struct uvc_format_mjpeg {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bFormatIndex;
-       __u8  bNumFrameDescriptors;
-       __u8  bmFlags;
-       __u8  bDefaultFrameIndex;
-       __u8  bAspectRatioX;
-       __u8  bAspectRatioY;
-       __u8  bmInterfaceFlags;
-       __u8  bCopyProtect;
-} __attribute__((__packed__));
-
-struct uvc_frame_mjpeg {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bFrameIndex;
-       __u8  bmCapabilities;
-       __u16 wWidth;
-       __u16 wHeight;
-       __u32 dwMinBitRate;
-       __u32 dwMaxBitRate;
-       __u32 dwMaxVideoFrameBufferSize;
-       __u32 dwDefaultFrameInterval;
-       __u8  bFrameIntervalType;
-       __u32 dwFrameInterval[];
-} __attribute__((__packed__));
-
-#define UVC_FRAME_MJPEG(n) \
-       uvc_frame_mjpeg_##n
-
-#define DECLARE_UVC_FRAME_MJPEG(n)                             \
-struct UVC_FRAME_MJPEG(n) {                                    \
-       __u8  bLength;                                          \
-       __u8  bDescriptorType;                                  \
-       __u8  bDescriptorSubType;                               \
-       __u8  bFrameIndex;                                      \
-       __u8  bmCapabilities;                                   \
-       __u16 wWidth;                                           \
-       __u16 wHeight;                                          \
-       __u32 dwMinBitRate;                                     \
-       __u32 dwMaxBitRate;                                     \
-       __u32 dwMaxVideoFrameBufferSize;                        \
-       __u32 dwDefaultFrameInterval;                           \
-       __u8  bFrameIntervalType;                               \
-       __u32 dwFrameInterval[n];                               \
-} __attribute__ ((packed))
-
-struct uvc_color_matching_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDescriptorSubType;
-       __u8  bColorPrimaries;
-       __u8  bTransferCharacteristics;
-       __u8  bMatrixCoefficients;
-} __attribute__((__packed__));
-
-#define UVC_DT_INPUT_HEADER                    1
-#define UVC_DT_OUTPUT_HEADER                   2
-#define UVC_DT_FORMAT_UNCOMPRESSED             4
-#define UVC_DT_FRAME_UNCOMPRESSED              5
-#define UVC_DT_FORMAT_MJPEG                    6
-#define UVC_DT_FRAME_MJPEG                     7
-#define UVC_DT_COLOR_MATCHING                  13
-
-#define UVC_DT_INPUT_HEADER_SIZE(n, p)         (13+(n*p))
-#define UVC_DT_OUTPUT_HEADER_SIZE(n, p)                (9+(n*p))
-#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE                27
-#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n)      (26+4*(n))
-#define UVC_DT_FORMAT_MJPEG_SIZE               11
-#define UVC_DT_FRAME_MJPEG_SIZE(n)             (26+4*(n))
-#define UVC_DT_COLOR_MATCHING_SIZE             6
+#include <linux/usb/video.h>
 
 extern int uvc_bind_config(struct usb_configuration *c,
                           const struct uvc_descriptor_header * const *control,
index d0b8bde59e59effdff3df5e5d84b5a79a817903d..eafa6d2c5ed734b278eaf1d34c69ab8f3290e383 100644 (file)
@@ -30,7 +30,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
 
        pdata = pdev->dev.platform_data;
 
-       if (!cpu_is_mx35()) {
+       if (!cpu_is_mx35() && !cpu_is_mx25()) {
                mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
                if (IS_ERR(mxc_ahb_clk))
                        return PTR_ERR(mxc_ahb_clk);
index e92454cddd7de095709c791aee97b715d0e99f33..5b7919460fd2302c1d79ed7c5e5fff42f351d80e 100644 (file)
@@ -47,39 +47,6 @@ struct uvc_event
 #define UVC_INTF_CONTROL               0
 #define UVC_INTF_STREAMING             1
 
-/* ------------------------------------------------------------------------
- * UVC constants & structures
- */
-
-/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
-#define UVC_STREAM_EOH                         (1 << 7)
-#define UVC_STREAM_ERR                         (1 << 6)
-#define UVC_STREAM_STI                         (1 << 5)
-#define UVC_STREAM_RES                         (1 << 4)
-#define UVC_STREAM_SCR                         (1 << 3)
-#define UVC_STREAM_PTS                         (1 << 2)
-#define UVC_STREAM_EOF                         (1 << 1)
-#define UVC_STREAM_FID                         (1 << 0)
-
-struct uvc_streaming_control {
-       __u16 bmHint;
-       __u8  bFormatIndex;
-       __u8  bFrameIndex;
-       __u32 dwFrameInterval;
-       __u16 wKeyFrameRate;
-       __u16 wPFrameRate;
-       __u16 wCompQuality;
-       __u16 wCompWindowSize;
-       __u16 wDelay;
-       __u32 dwMaxVideoFrameSize;
-       __u32 dwMaxPayloadTransferSize;
-       __u32 dwClockFrequency;
-       __u8  bmFramingInfo;
-       __u8  bPreferedVersion;
-       __u8  bMinVersion;
-       __u8  bMaxVersion;
-} __attribute__((__packed__));
-
 /* ------------------------------------------------------------------------
  * Debugging, printing and logging
  */
@@ -137,9 +104,6 @@ extern unsigned int uvc_gadget_trace_param;
 #define UVC_MAX_REQUEST_SIZE                   64
 #define UVC_MAX_EVENTS                         4
 
-#define USB_DT_INTERFACE_ASSOCIATION_SIZE      8
-#define USB_CLASS_MISC                         0xef
-
 /* ------------------------------------------------------------------------
  * Structures
  */
index f5f3030cc41671ca249fcb3917823c5d578acda3..288d21155abe77e655d30fd31314ea4d22d3a12b 100644 (file)
@@ -90,7 +90,7 @@ DECLARE_UVC_HEADER_DESCRIPTOR(1);
 static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
        .bLength                = UVC_DT_HEADER_SIZE(1),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_HEADER,
+       .bDescriptorSubType     = UVC_VC_HEADER,
        .bcdUVC                 = cpu_to_le16(0x0100),
        .wTotalLength           = 0, /* dynamic */
        .dwClockFrequency       = cpu_to_le32(48000000),
@@ -101,7 +101,7 @@ static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
 static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
        .bLength                = UVC_DT_CAMERA_TERMINAL_SIZE(3),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_INPUT_TERMINAL,
+       .bDescriptorSubType     = UVC_VC_INPUT_TERMINAL,
        .bTerminalID            = 1,
        .wTerminalType          = cpu_to_le16(0x0201),
        .bAssocTerminal         = 0,
@@ -118,7 +118,7 @@ static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
 static const struct uvc_processing_unit_descriptor uvc_processing = {
        .bLength                = UVC_DT_PROCESSING_UNIT_SIZE(2),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_PROCESSING_UNIT,
+       .bDescriptorSubType     = UVC_VC_PROCESSING_UNIT,
        .bUnitID                = 2,
        .bSourceID              = 1,
        .wMaxMultiplier         = cpu_to_le16(16*1024),
@@ -131,7 +131,7 @@ static const struct uvc_processing_unit_descriptor uvc_processing = {
 static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
        .bLength                = UVC_DT_OUTPUT_TERMINAL_SIZE,
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_OUTPUT_TERMINAL,
+       .bDescriptorSubType     = UVC_VC_OUTPUT_TERMINAL,
        .bTerminalID            = 3,
        .wTerminalType          = cpu_to_le16(0x0101),
        .bAssocTerminal         = 0,
@@ -144,7 +144,7 @@ DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
 static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
        .bLength                = UVC_DT_INPUT_HEADER_SIZE(1, 2),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_INPUT_HEADER,
+       .bDescriptorSubType     = UVC_VS_INPUT_HEADER,
        .bNumFormats            = 2,
        .wTotalLength           = 0, /* dynamic */
        .bEndpointAddress       = 0, /* dynamic */
@@ -161,7 +161,7 @@ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
 static const struct uvc_format_uncompressed uvc_format_yuv = {
        .bLength                = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_FORMAT_UNCOMPRESSED,
+       .bDescriptorSubType     = UVC_VS_FORMAT_UNCOMPRESSED,
        .bFormatIndex           = 1,
        .bNumFrameDescriptors   = 2,
        .guidFormat             =
@@ -181,7 +181,7 @@ DECLARE_UVC_FRAME_UNCOMPRESSED(3);
 static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
        .bLength                = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_FRAME_UNCOMPRESSED,
+       .bDescriptorSubType     = UVC_VS_FRAME_UNCOMPRESSED,
        .bFrameIndex            = 1,
        .bmCapabilities         = 0,
        .wWidth                 = cpu_to_le16(640),
@@ -199,7 +199,7 @@ static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
 static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
        .bLength                = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_FRAME_UNCOMPRESSED,
+       .bDescriptorSubType     = UVC_VS_FRAME_UNCOMPRESSED,
        .bFrameIndex            = 2,
        .bmCapabilities         = 0,
        .wWidth                 = cpu_to_le16(1280),
@@ -215,7 +215,7 @@ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
 static const struct uvc_format_mjpeg uvc_format_mjpg = {
        .bLength                = UVC_DT_FORMAT_MJPEG_SIZE,
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_FORMAT_MJPEG,
+       .bDescriptorSubType     = UVC_VS_FORMAT_MJPEG,
        .bFormatIndex           = 2,
        .bNumFrameDescriptors   = 2,
        .bmFlags                = 0,
@@ -232,7 +232,7 @@ DECLARE_UVC_FRAME_MJPEG(3);
 static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
        .bLength                = UVC_DT_FRAME_MJPEG_SIZE(3),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_FRAME_MJPEG,
+       .bDescriptorSubType     = UVC_VS_FRAME_MJPEG,
        .bFrameIndex            = 1,
        .bmCapabilities         = 0,
        .wWidth                 = cpu_to_le16(640),
@@ -250,7 +250,7 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
 static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
        .bLength                = UVC_DT_FRAME_MJPEG_SIZE(1),
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_FRAME_MJPEG,
+       .bDescriptorSubType     = UVC_VS_FRAME_MJPEG,
        .bFrameIndex            = 2,
        .bmCapabilities         = 0,
        .wWidth                 = cpu_to_le16(1280),
@@ -266,7 +266,7 @@ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
 static const struct uvc_color_matching_descriptor uvc_color_matching = {
        .bLength                = UVC_DT_COLOR_MATCHING_SIZE,
        .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_DT_COLOR_MATCHING,
+       .bDescriptorSubType     = UVC_VS_COLORFORMAT,
        .bColorPrimaries        = 1,
        .bTransferCharacteristics       = 1,
        .bMatrixCoefficients    = 4,
index bd4027745aa7039e5cfcdd6b1bf4057ad8569d85..a8ad8ac120a2bfe733eaa2d151ad528afc15685d 100644 (file)
@@ -182,7 +182,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        }
        clk_enable(priv->usbclk);
 
-       if (!cpu_is_mx35()) {
+       if (!cpu_is_mx35() && !cpu_is_mx25()) {
                priv->ahbclk = clk_get(dev, "usb_ahb");
                if (IS_ERR(priv->ahbclk)) {
                        ret = PTR_ERR(priv->ahbclk);
index 3a561df2e8a29d7b020913beef4a86fb705836a3..0c1afd13ddd3055be4c61abd56253edf38f7ac36 100644 (file)
@@ -388,6 +388,7 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                pseudo_val |= convert_bitfield(red, &var->red);
                pseudo_val |= convert_bitfield(green, &var->green);
                pseudo_val |= convert_bitfield(blue, &var->blue);
+               ret = 0;
                break;
        }
 
@@ -436,6 +437,8 @@ static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
        cyber2000fb_writeb(i | 4, 0x3cf, cfb);
        cyber2000fb_writeb(val, 0x3c6, cfb);
        cyber2000fb_writeb(i, 0x3cf, cfb);
+       /* prevent card lock-up observed on x86 with CyberPro 2000 */
+       cyber2000fb_readb(0x3cf, cfb);
 }
 
 static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
index b4b6deceed153ae1b11bab3384249113359ec2c0..43f0639b1c10b7a7ede287df51b0ab28277031c1 100644 (file)
@@ -175,6 +175,7 @@ struct imxfb_info {
 
        struct imx_fb_videomode *mode;
        int                     num_modes;
+       struct backlight_device *bl;
 
        void (*lcd_power)(int);
        void (*backlight_power)(int);
@@ -449,6 +450,73 @@ static int imxfb_set_par(struct fb_info *info)
        return 0;
 }
 
+
+
+static int imxfb_bl_get_brightness(struct backlight_device *bl)
+{
+       struct imxfb_info *fbi = bl_get_data(bl);
+
+       return readl(fbi->regs + LCDC_PWMR) & 0xFF;
+}
+
+static int imxfb_bl_update_status(struct backlight_device *bl)
+{
+       struct imxfb_info *fbi = bl_get_data(bl);
+       int brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               brightness = 0;
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness;
+
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               clk_enable(fbi->clk);
+       writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               clk_disable(fbi->clk);
+
+       return 0;
+}
+
+static const struct backlight_ops imxfb_lcdc_bl_ops = {
+       .update_status = imxfb_bl_update_status,
+       .get_brightness = imxfb_bl_get_brightness,
+};
+
+static void imxfb_init_backlight(struct imxfb_info *fbi)
+{
+       struct backlight_properties props;
+       struct backlight_device *bl;
+
+       if (fbi->bl)
+               return;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.max_brightness = 0xff;
+       writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+
+       bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi,
+                                      &imxfb_lcdc_bl_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&fbi->pdev->dev, "error %ld on backlight register\n",
+                               PTR_ERR(bl));
+               return;
+       }
+
+       fbi->bl = bl;
+       bl->props.power = FB_BLANK_UNBLANK;
+       bl->props.fb_blank = FB_BLANK_UNBLANK;
+       bl->props.brightness = imxfb_bl_get_brightness(bl);
+}
+
+static void imxfb_exit_backlight(struct imxfb_info *fbi)
+{
+       if (fbi->bl)
+               backlight_device_unregister(fbi->bl);
+}
+
 static void imxfb_enable_controller(struct imxfb_info *fbi)
 {
        pr_debug("Enabling LCD controller\n");
@@ -579,7 +647,6 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
                        fbi->regs + LCDC_SIZE);
 
        writel(fbi->pcr, fbi->regs + LCDC_PCR);
-       writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
        writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
        writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
 
@@ -779,6 +846,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
        }
 
        imxfb_enable_controller(fbi);
+       fbi->pdev = pdev;
+       imxfb_init_backlight(fbi);
 
        return 0;
 
@@ -816,6 +885,7 @@ static int __devexit imxfb_remove(struct platform_device *pdev)
 
        imxfb_disable_controller(fbi);
 
+       imxfb_exit_backlight(fbi);
        unregister_framebuffer(info);
 
        pdata = pdev->dev.platform_data;
index 1f8eb70e2937bbcb101d14ffe9b7238bad79b570..07fbb8a733bb5ecd46c569e56d5ebe0c99714e61 100644 (file)
@@ -592,7 +592,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
        r = omapdss_sdi_display_enable(dssdev);
        if (r) {
                pr_err("%s sdi enable failed\n", __func__);
-               return r;
+               goto fail_unlock;
        }
 
        /*FIXME tweak me */
@@ -633,6 +633,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
        return acx565akm_bl_update_status(md->bl_dev);
 fail:
        omapdss_sdi_display_disable(dssdev);
+fail_unlock:
+       mutex_unlock(&md->mutex);
        return r;
 }
 
index 3b1237ad85ed384a3adba6dfe07451d2a732ed11..f6fdc2085f3e20147a4e9b0ae8ab4080c4fa4728 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/completion.h>
 #include <linux/debugfs.h>
 #include <linux/jiffies.h>
@@ -525,10 +525,8 @@ early_param("vram", omap_vram_early_vram);
  * Called from map_io. We need to call to this early enough so that we
  * can reserve the fixed SDRAM regions before VM could get hold of them.
  */
-void __init omap_vram_reserve_sdram(void)
+void __init omap_vram_reserve_sdram_memblock(void)
 {
-       struct bootmem_data     *bdata;
-       unsigned long           sdram_start, sdram_size;
        u32 paddr;
        u32 size = 0;
 
@@ -555,29 +553,28 @@ void __init omap_vram_reserve_sdram(void)
 
        size = PAGE_ALIGN(size);
 
-       bdata = NODE_DATA(0)->bdata;
-       sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
-       sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
-
        if (paddr) {
-               if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
-                               paddr + size > sdram_start + sdram_size) {
+               struct memblock_property res;
+
+               res.base = paddr;
+               res.size = size;
+               if ((paddr & ~PAGE_MASK) || memblock_find(&res) ||
+                   res.base != paddr || res.size != size) {
                        pr_err("Illegal SDRAM region for VRAM\n");
                        return;
                }
 
-               if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
-                       pr_err("FB: failed to reserve VRAM\n");
+               if (memblock_is_region_reserved(paddr, size)) {
+                       pr_err("FB: failed to reserve VRAM - busy\n");
                        return;
                }
-       } else {
-               if (size > sdram_size) {
-                       pr_err("Illegal SDRAM size for VRAM\n");
+
+               if (memblock_reserve(paddr, size) < 0) {
+                       pr_err("FB: failed to reserve VRAM - no memory\n");
                        return;
                }
-
-               paddr = virt_to_phys(alloc_bootmem_pages(size));
-               BUG_ON(paddr & ~PAGE_MASK);
+       } else {
+               paddr = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_REAL_LIMIT);
        }
 
        omap_vram_add_region(paddr, size);
index 1a940ec7af611859aa01b012e866c66fdc8cf9e0..91fba025fcbea22cceeabd19c979bd2281dd040a 100644 (file)
@@ -8,6 +8,8 @@ obj-$(CONFIG_9P_FS) := 9p.o
        vfs_dir.o \
        vfs_dentry.o \
        v9fs.o \
-       fid.o
+       fid.o  \
+       xattr.o \
+       xattr_user.o
 
 9p-$(CONFIG_9P_FSCACHE) += cache.o
index 7317b39b28159b2e712de1eec7bed5fce2312b3a..358563689064df61c9b81713ad8bb8911c6518bd 100644 (file)
@@ -97,6 +97,34 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
        return ret;
 }
 
+/*
+ * We need to hold v9ses->rename_sem as long as we hold references
+ * to returned path array. Array element contain pointers to
+ * dentry names.
+ */
+static int build_path_from_dentry(struct v9fs_session_info *v9ses,
+                                 struct dentry *dentry, char ***names)
+{
+       int n = 0, i;
+       char **wnames;
+       struct dentry *ds;
+
+       for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
+               n++;
+
+       wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
+       if (!wnames)
+               goto err_out;
+
+       for (ds = dentry, i = (n-1); i >= 0; i--, ds = ds->d_parent)
+               wnames[i] = (char  *)ds->d_name.name;
+
+       *names = wnames;
+       return n;
+err_out:
+       return -ENOMEM;
+}
+
 /**
  * v9fs_fid_lookup - lookup for a fid, try to walk if not found
  * @dentry: dentry to look for fid in
@@ -112,7 +140,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        int i, n, l, clone, any, access;
        u32 uid;
        struct p9_fid *fid, *old_fid = NULL;
-       struct dentry *d, *ds;
+       struct dentry *ds;
        struct v9fs_session_info *v9ses;
        char **wnames, *uname;
 
@@ -139,49 +167,62 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        fid = v9fs_fid_find(dentry, uid, any);
        if (fid)
                return fid;
-
+       /*
+        * we don't have a matching fid. To do a TWALK we need
+        * parent fid. We need to prevent rename when we want to
+        * look at the parent.
+        */
+       down_read(&v9ses->rename_sem);
        ds = dentry->d_parent;
        fid = v9fs_fid_find(ds, uid, any);
-       if (!fid) { /* walk from the root */
-               n = 0;
-               for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
-                       n++;
+       if (fid) {
+               /* Found the parent fid do a lookup with that */
+               fid = p9_client_walk(fid, 1, (char **)&dentry->d_name.name, 1);
+               goto fid_out;
+       }
+       up_read(&v9ses->rename_sem);
 
-               fid = v9fs_fid_find(ds, uid, any);
-               if (!fid) { /* the user is not attached to the fs yet */
-                       if (access == V9FS_ACCESS_SINGLE)
-                               return ERR_PTR(-EPERM);
+       /* start from the root and try to do a lookup */
+       fid = v9fs_fid_find(dentry->d_sb->s_root, uid, any);
+       if (!fid) {
+               /* the user is not attached to the fs yet */
+               if (access == V9FS_ACCESS_SINGLE)
+                       return ERR_PTR(-EPERM);
 
-                       if (v9fs_proto_dotu(v9ses))
+               if (v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses))
                                uname = NULL;
-                       else
-                               uname = v9ses->uname;
+               else
+                       uname = v9ses->uname;
 
-                       fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
-                               v9ses->aname);
-
-                       if (IS_ERR(fid))
-                               return fid;
-
-                       v9fs_fid_add(ds, fid);
-               }
-       } else /* walk from the parent */
-               n = 1;
+               fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
+                                      v9ses->aname);
+               if (IS_ERR(fid))
+                       return fid;
 
-       if (ds == dentry)
+               v9fs_fid_add(dentry->d_sb->s_root, fid);
+       }
+       /* If we are root ourself just return that */
+       if (dentry->d_sb->s_root == dentry)
                return fid;
-
-       wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
-       if (!wnames)
-               return ERR_PTR(-ENOMEM);
-
-       for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent)
-               wnames[i] = (char *) d->d_name.name;
-
+       /*
+        * Do a multipath walk with attached root.
+        * When walking parent we need to make sure we
+        * don't have a parallel rename happening
+        */
+       down_read(&v9ses->rename_sem);
+       n  = build_path_from_dentry(v9ses, dentry, &wnames);
+       if (n < 0) {
+               fid = ERR_PTR(n);
+               goto err_out;
+       }
        clone = 1;
        i = 0;
        while (i < n) {
                l = min(n - i, P9_MAXWELEM);
+               /*
+                * We need to hold rename lock when doing a multipath
+                * walk to ensure none of the patch component change
+                */
                fid = p9_client_walk(fid, l, &wnames[i], clone);
                if (IS_ERR(fid)) {
                        if (old_fid) {
@@ -193,15 +234,17 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
                                p9_client_clunk(old_fid);
                        }
                        kfree(wnames);
-                       return fid;
+                       goto err_out;
                }
                old_fid = fid;
                i += l;
                clone = 0;
        }
-
        kfree(wnames);
+fid_out:
        v9fs_fid_add(dentry, fid);
+err_out:
+       up_read(&v9ses->rename_sem);
        return fid;
 }
 
index f8b86e92cd660ef9da7e026be6a06fb7de4863fb..38dc0e0675998413dd205d13674412eff054ec4e 100644 (file)
@@ -237,6 +237,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
                __putname(v9ses->uname);
                return ERR_PTR(-ENOMEM);
        }
+       init_rwsem(&v9ses->rename_sem);
 
        rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);
        if (rc) {
@@ -278,7 +279,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
 
        /* for legacy mode, fall back to V9FS_ACCESS_ANY */
-       if (!v9fs_proto_dotu(v9ses) &&
+       if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
                ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
 
                v9ses->flags &= ~V9FS_ACCESS_MASK;
index bec4d0bcb4585d1f41c89406ef9eeb9eb6421115..4c963c9fc41fdf17107604354b17c4dfd06f0fae 100644 (file)
@@ -104,6 +104,7 @@ struct v9fs_session_info {
        struct p9_client *clnt; /* 9p client */
        struct list_head slist; /* list of sessions registered with v9fs */
        struct backing_dev_info bdi;
+       struct rw_semaphore rename_sem;
 };
 
 struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
index 32ef4009d030063328d9811a9bcaf7daaf5e762d..f47c6bbb01b308115eedf8cb228e5dc694fe6560 100644 (file)
@@ -55,6 +55,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode);
 void v9fs_clear_inode(struct inode *inode);
 ino_t v9fs_qid2ino(struct p9_qid *qid);
 void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
+void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
 int v9fs_dir_release(struct inode *inode, struct file *filp);
 int v9fs_file_open(struct inode *inode, struct file *file);
 void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
index 36d961f342af5b95e4e79c42f4a82b5893a73823..16c8a2a98c1bb6b93fbc8634cb1986cf555bad0e 100644 (file)
@@ -87,29 +87,19 @@ static void p9stat_init(struct p9_wstat *stbuf)
 }
 
 /**
- * v9fs_dir_readdir - read a directory
+ * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
  * @filp: opened file structure
- * @dirent: directory structure ???
- * @filldir: function to populate directory structure ???
+ * @buflen: Length in bytes of buffer to allocate
  *
  */
 
-static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int v9fs_alloc_rdir_buf(struct file *filp, int buflen)
 {
-       int over;
-       struct p9_wstat st;
-       int err = 0;
-       struct p9_fid *fid;
-       int buflen;
-       int reclen = 0;
        struct p9_rdir *rdir;
+       struct p9_fid *fid;
+       int err = 0;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
        fid = filp->private_data;
-
-       buflen = fid->clnt->msize - P9_IOHDRSZ;
-
-       /* allocate rdir on demand */
        if (!fid->rdir) {
                rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
 
@@ -128,6 +118,36 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
                spin_unlock(&filp->f_dentry->d_lock);
                kfree(rdir);
        }
+exit:
+       return err;
+}
+
+/**
+ * v9fs_dir_readdir - read a directory
+ * @filp: opened file structure
+ * @dirent: directory structure ???
+ * @filldir: function to populate directory structure ???
+ *
+ */
+
+static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       int over;
+       struct p9_wstat st;
+       int err = 0;
+       struct p9_fid *fid;
+       int buflen;
+       int reclen = 0;
+       struct p9_rdir *rdir;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+       fid = filp->private_data;
+
+       buflen = fid->clnt->msize - P9_IOHDRSZ;
+
+       err = v9fs_alloc_rdir_buf(filp, buflen);
+       if (err)
+               goto exit;
        rdir = (struct p9_rdir *) fid->rdir;
 
        err = mutex_lock_interruptible(&rdir->mutex);
@@ -176,6 +196,88 @@ exit:
        return err;
 }
 
+/**
+ * v9fs_dir_readdir_dotl - read a directory
+ * @filp: opened file structure
+ * @dirent: buffer to fill dirent structures
+ * @filldir: function to populate dirent structures
+ *
+ */
+static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
+                                               filldir_t filldir)
+{
+       int over;
+       int err = 0;
+       struct p9_fid *fid;
+       int buflen;
+       struct p9_rdir *rdir;
+       struct p9_dirent curdirent;
+       u64 oldoffset = 0;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+       fid = filp->private_data;
+
+       buflen = fid->clnt->msize - P9_READDIRHDRSZ;
+
+       err = v9fs_alloc_rdir_buf(filp, buflen);
+       if (err)
+               goto exit;
+       rdir = (struct p9_rdir *) fid->rdir;
+
+       err = mutex_lock_interruptible(&rdir->mutex);
+       if (err)
+               return err;
+
+       while (err == 0) {
+               if (rdir->tail == rdir->head) {
+                       err = p9_client_readdir(fid, rdir->buf, buflen,
+                                                               filp->f_pos);
+                       if (err <= 0)
+                               goto unlock_and_exit;
+
+                       rdir->head = 0;
+                       rdir->tail = err;
+               }
+
+               while (rdir->head < rdir->tail) {
+
+                       err = p9dirent_read(rdir->buf + rdir->head,
+                                               buflen - rdir->head, &curdirent,
+                                               fid->clnt->proto_version);
+                       if (err < 0) {
+                               P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
+                               err = -EIO;
+                               goto unlock_and_exit;
+                       }
+
+                       /* d_off in dirent structure tracks the offset into
+                        * the next dirent in the dir. However, filldir()
+                        * expects offset into the current dirent. Hence
+                        * while calling filldir send the offset from the
+                        * previous dirent structure.
+                        */
+                       over = filldir(dirent, curdirent.d_name,
+                                       strlen(curdirent.d_name),
+                                       oldoffset, v9fs_qid2ino(&curdirent.qid),
+                                       curdirent.d_type);
+                       oldoffset = curdirent.d_off;
+
+                       if (over) {
+                               err = 0;
+                               goto unlock_and_exit;
+                       }
+
+                       filp->f_pos = curdirent.d_off;
+                       rdir->head += err;
+               }
+       }
+
+unlock_and_exit:
+       mutex_unlock(&rdir->mutex);
+exit:
+       return err;
+}
+
 
 /**
  * v9fs_dir_release - close a directory
@@ -207,7 +309,7 @@ const struct file_operations v9fs_dir_operations = {
 const struct file_operations v9fs_dir_operations_dotl = {
        .read = generic_read_dir,
        .llseek = generic_file_llseek,
-       .readdir = v9fs_dir_readdir,
+       .readdir = v9fs_dir_readdir_dotl,
        .open = v9fs_file_open,
        .release = v9fs_dir_release,
 };
index 2bedc6c94fc2c805f407e4fb5ad7970e36f27a83..e97c92bd6f16d51c38fa3f98909e62ff9225e2b6 100644 (file)
@@ -59,9 +59,13 @@ int v9fs_file_open(struct inode *inode, struct file *file)
        struct p9_fid *fid;
        int omode;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
+       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
        v9ses = v9fs_inode2v9ses(inode);
-       omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses));
+       if (v9fs_proto_dotl(v9ses))
+               omode = file->f_flags;
+       else
+               omode = v9fs_uflags2omode(file->f_flags,
+                                       v9fs_proto_dotu(v9ses));
        fid = file->private_data;
        if (!fid) {
                fid = v9fs_fid_clone(file->f_path.dentry);
@@ -73,11 +77,12 @@ int v9fs_file_open(struct inode *inode, struct file *file)
                        p9_client_clunk(fid);
                        return err;
                }
-               if (omode & P9_OTRUNC) {
+               if (file->f_flags & O_TRUNC) {
                        i_size_write(inode, 0);
                        inode->i_blocks = 0;
                }
-               if ((file->f_flags & O_APPEND) && (!v9fs_proto_dotu(v9ses)))
+               if ((file->f_flags & O_APPEND) &&
+                       (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
                        generic_file_llseek(file, 0, SEEK_END);
        }
 
@@ -139,7 +144,7 @@ ssize_t
 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
               u64 offset)
 {
-       int n, total;
+       int n, total, size;
        struct p9_fid *fid = filp->private_data;
 
        P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
@@ -147,6 +152,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
 
        n = 0;
        total = 0;
+       size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
        do {
                n = p9_client_read(fid, data, udata, offset, count);
                if (n <= 0)
@@ -160,7 +166,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
                offset += n;
                count -= n;
                total += n;
-       } while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ));
+       } while (count > 0 && n == size);
 
        if (n < 0)
                total = n;
@@ -183,11 +189,13 @@ v9fs_file_read(struct file *filp, char __user *udata, size_t count,
 {
        int ret;
        struct p9_fid *fid;
+       size_t size;
 
        P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
        fid = filp->private_data;
 
-       if (count > (fid->clnt->msize - P9_IOHDRSZ))
+       size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
+       if (count > size)
                ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
        else
                ret = p9_client_read(fid, NULL, udata, *offset, count);
@@ -224,9 +232,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
        fid = filp->private_data;
        clnt = fid->clnt;
 
-       rsize = fid->iounit;
-       if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
-               rsize = clnt->msize - P9_IOHDRSZ;
+       rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
 
        do {
                if (count < rsize)
index 4331b3b5ee1c978a8a7b4b719ed6da14ede32cff..6e94f3247cec5fb7e354583c31ded72254a3b623 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/idr.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/xattr.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -42,6 +43,7 @@
 #include "v9fs_vfs.h"
 #include "fid.h"
 #include "cache.h"
+#include "xattr.h"
 
 static const struct inode_operations v9fs_dir_inode_operations;
 static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -235,6 +237,41 @@ void v9fs_destroy_inode(struct inode *inode)
 }
 #endif
 
+/**
+ * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
+ * new file system object. This checks the S_ISGID to determine the owning
+ * group of the new file system object.
+ */
+
+static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
+{
+       BUG_ON(dir_inode == NULL);
+
+       if (dir_inode->i_mode & S_ISGID) {
+               /* set_gid bit is set.*/
+               return dir_inode->i_gid;
+       }
+       return current_fsgid();
+}
+
+/**
+ * v9fs_dentry_from_dir_inode - helper function to get the dentry from
+ * dir inode.
+ *
+ */
+
+static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)
+{
+       struct dentry *dentry;
+
+       spin_lock(&dcache_lock);
+       /* Directory should have only one entry. */
+       BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));
+       dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
+       spin_unlock(&dcache_lock);
+       return dentry;
+}
+
 /**
  * v9fs_get_inode - helper function to setup an inode
  * @sb: superblock
@@ -267,7 +304,13 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
        case S_IFBLK:
        case S_IFCHR:
        case S_IFSOCK:
-               if (!v9fs_proto_dotu(v9ses)) {
+               if (v9fs_proto_dotl(v9ses)) {
+                       inode->i_op = &v9fs_file_inode_operations_dotl;
+                       inode->i_fop = &v9fs_file_operations_dotl;
+               } else if (v9fs_proto_dotu(v9ses)) {
+                       inode->i_op = &v9fs_file_inode_operations;
+                       inode->i_fop = &v9fs_file_operations;
+               } else {
                        P9_DPRINTK(P9_DEBUG_ERROR,
                                   "special files without extended mode\n");
                        err = -EINVAL;
@@ -396,23 +439,14 @@ void v9fs_clear_inode(struct inode *inode)
 #endif
 }
 
-/**
- * v9fs_inode_from_fid - populate an inode by issuing a attribute request
- * @v9ses: session information
- * @fid: fid to issue attribute request for
- * @sb: superblock on which to create inode
- *
- */
-
 static struct inode *
-v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid,
        struct super_block *sb)
 {
        int err, umode;
-       struct inode *ret;
+       struct inode *ret = NULL;
        struct p9_wstat *st;
 
-       ret = NULL;
        st = p9_client_stat(fid);
        if (IS_ERR(st))
                return ERR_CAST(st);
@@ -433,15 +467,62 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
 #endif
        p9stat_free(st);
        kfree(st);
-
        return ret;
-
 error:
        p9stat_free(st);
        kfree(st);
        return ERR_PTR(err);
 }
 
+static struct inode *
+v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+       struct super_block *sb)
+{
+       struct inode *ret = NULL;
+       int err;
+       struct p9_stat_dotl *st;
+
+       st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+       if (IS_ERR(st))
+               return ERR_CAST(st);
+
+       ret = v9fs_get_inode(sb, st->st_mode);
+       if (IS_ERR(ret)) {
+               err = PTR_ERR(ret);
+               goto error;
+       }
+
+       v9fs_stat2inode_dotl(st, ret);
+       ret->i_ino = v9fs_qid2ino(&st->qid);
+#ifdef CONFIG_9P_FSCACHE
+       v9fs_vcookie_set_qid(ret, &st->qid);
+       v9fs_cache_inode_get_cookie(ret);
+#endif
+       kfree(st);
+       return ret;
+error:
+       kfree(st);
+       return ERR_PTR(err);
+}
+
+/**
+ * v9fs_inode_from_fid - Helper routine to populate an inode by
+ * issuing a attribute request
+ * @v9ses: session information
+ * @fid: fid to issue attribute request for
+ * @sb: superblock on which to create inode
+ *
+ */
+static inline struct inode *
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+                       struct super_block *sb)
+{
+       if (v9fs_proto_dotl(v9ses))
+               return v9fs_inode_dotl(v9ses, fid, sb);
+       else
+               return v9fs_inode(v9ses, fid, sb);
+}
+
 /**
  * v9fs_remove - helper function to remove files and directories
  * @dir: directory inode that is being deleted
@@ -562,6 +643,118 @@ error:
        return ERR_PTR(err);
 }
 
+/**
+ * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
+ * @dir: directory inode that is being created
+ * @dentry:  dentry that is being deleted
+ * @mode: create permissions
+ * @nd: path information
+ *
+ */
+
+static int
+v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
+               struct nameidata *nd)
+{
+       int err = 0;
+       char *name = NULL;
+       gid_t gid;
+       int flags;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid = NULL;
+       struct p9_fid *dfid, *ofid;
+       struct file *filp;
+       struct p9_qid qid;
+       struct inode *inode;
+
+       v9ses = v9fs_inode2v9ses(dir);
+       if (nd && nd->flags & LOOKUP_OPEN)
+               flags = nd->intent.open.flags - 1;
+       else
+               flags = O_RDWR;
+
+       name = (char *) dentry->d_name.name;
+       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
+                       "mode:0x%x\n", name, flags, mode);
+
+       dfid = v9fs_fid_lookup(dentry->d_parent);
+       if (IS_ERR(dfid)) {
+               err = PTR_ERR(dfid);
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               return err;
+       }
+
+       /* clone a fid to use for creation */
+       ofid = p9_client_walk(dfid, 0, NULL, 1);
+       if (IS_ERR(ofid)) {
+               err = PTR_ERR(ofid);
+               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+               return err;
+       }
+
+       gid = v9fs_get_fsgid_for_create(dir);
+       err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
+       if (err < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS,
+                               "p9_client_open_dotl failed in creat %d\n",
+                               err);
+               goto error;
+       }
+
+       /* No need to populate the inode if we are not opening the file AND
+        * not in cached mode.
+        */
+       if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) {
+               /* Not in cached mode. No need to populate inode with stat */
+               dentry->d_op = &v9fs_dentry_operations;
+               p9_client_clunk(ofid);
+               d_instantiate(dentry, NULL);
+               return 0;
+       }
+
+       /* Now walk from the parent so we can get an unopened fid. */
+       fid = p9_client_walk(dfid, 1, &name, 1);
+       if (IS_ERR(fid)) {
+               err = PTR_ERR(fid);
+               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+               fid = NULL;
+               goto error;
+       }
+
+       /* instantiate inode and assign the unopened fid to dentry */
+       inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
+               P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
+               goto error;
+       }
+       dentry->d_op = &v9fs_cached_dentry_operations;
+       d_instantiate(dentry, inode);
+       err = v9fs_fid_add(dentry, fid);
+       if (err < 0)
+               goto error;
+
+       /* if we are opening a file, assign the open fid to the file */
+       if (nd && nd->flags & LOOKUP_OPEN) {
+               filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
+               if (IS_ERR(filp)) {
+                       p9_client_clunk(ofid);
+                       return PTR_ERR(filp);
+               }
+               filp->private_data = ofid;
+       } else
+               p9_client_clunk(ofid);
+
+       return 0;
+
+error:
+       if (ofid)
+               p9_client_clunk(ofid);
+       if (fid)
+               p9_client_clunk(fid);
+       return err;
+}
+
 /**
  * v9fs_vfs_create - VFS hook to create files
  * @dir: directory inode that is being created
@@ -652,6 +845,83 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        return err;
 }
 
+
+/**
+ * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory
+ * @dir:  inode that is being unlinked
+ * @dentry: dentry that is being unlinked
+ * @mode: mode for new directory
+ *
+ */
+
+static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
+                                       int mode)
+{
+       int err;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid = NULL, *dfid = NULL;
+       gid_t gid;
+       char *name;
+       struct inode *inode;
+       struct p9_qid qid;
+       struct dentry *dir_dentry;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       err = 0;
+       v9ses = v9fs_inode2v9ses(dir);
+
+       mode |= S_IFDIR;
+       dir_dentry = v9fs_dentry_from_dir_inode(dir);
+       dfid = v9fs_fid_lookup(dir_dentry);
+       if (IS_ERR(dfid)) {
+               err = PTR_ERR(dfid);
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               dfid = NULL;
+               goto error;
+       }
+
+       gid = v9fs_get_fsgid_for_create(dir);
+       if (gid < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+               goto error;
+       }
+
+       name = (char *) dentry->d_name.name;
+       err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
+       if (err < 0)
+               goto error;
+
+       /* instantiate inode and assign the unopened fid to the dentry */
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+               fid = p9_client_walk(dfid, 1, &name, 1);
+               if (IS_ERR(fid)) {
+                       err = PTR_ERR(fid);
+                       P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+                               err);
+                       fid = NULL;
+                       goto error;
+               }
+
+               inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+                               err);
+                       goto error;
+               }
+               dentry->d_op = &v9fs_cached_dentry_operations;
+               d_instantiate(dentry, inode);
+               err = v9fs_fid_add(dentry, fid);
+               if (err < 0)
+                       goto error;
+               fid = NULL;
+       }
+error:
+       if (fid)
+               p9_client_clunk(fid);
+       return err;
+}
+
 /**
  * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
  * @dir:  inode that is being walked from
@@ -678,6 +948,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 
        sb = dir->i_sb;
        v9ses = v9fs_inode2v9ses(dir);
+       /* We can walk d_parent because we hold the dir->i_mutex */
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid))
                return ERR_CAST(dfid);
@@ -785,27 +1056,33 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto clunk_olddir;
        }
 
+       down_write(&v9ses->rename_sem);
        if (v9fs_proto_dotl(v9ses)) {
                retval = p9_client_rename(oldfid, newdirfid,
                                        (char *) new_dentry->d_name.name);
                if (retval != -ENOSYS)
                        goto clunk_newdir;
        }
+       if (old_dentry->d_parent != new_dentry->d_parent) {
+               /*
+                * 9P .u can only handle file rename in the same directory
+                */
 
-       /* 9P can only handle file rename in the same directory */
-       if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
                P9_DPRINTK(P9_DEBUG_ERROR,
                                "old dir and new dir are different\n");
                retval = -EXDEV;
                goto clunk_newdir;
        }
-
        v9fs_blank_wstat(&wstat);
        wstat.muid = v9ses->uname;
        wstat.name = (char *) new_dentry->d_name.name;
        retval = p9_client_wstat(oldfid, &wstat);
 
 clunk_newdir:
+       if (!retval)
+               /* successful rename */
+               d_move(old_dentry, new_dentry);
+       up_write(&v9ses->rename_sem);
        p9_client_clunk(newdirfid);
 
 clunk_olddir:
@@ -853,6 +1130,42 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        return 0;
 }
 
+static int
+v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
+                struct kstat *stat)
+{
+       int err;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid;
+       struct p9_stat_dotl *st;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
+       err = -EPERM;
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
+               return simple_getattr(mnt, dentry, stat);
+
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
+
+       /* Ask for all the fields in stat structure. Server will return
+        * whatever it supports
+        */
+
+       st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
+       if (IS_ERR(st))
+               return PTR_ERR(st);
+
+       v9fs_stat2inode_dotl(st, dentry->d_inode);
+       generic_fillattr(dentry->d_inode, stat);
+       /* Change block size to what the server returned */
+       stat->blksize = st->st_blksize;
+
+       kfree(st);
+       return 0;
+}
+
 /**
  * v9fs_vfs_setattr - set file metadata
  * @dentry: file whose metadata to set
@@ -902,6 +1215,49 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
        return retval;
 }
 
+/**
+ * v9fs_vfs_setattr_dotl - set file metadata
+ * @dentry: file whose metadata to set
+ * @iattr: metadata assignment structure
+ *
+ */
+
+static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
+{
+       int retval;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid;
+       struct p9_iattr_dotl p9attr;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "\n");
+
+       retval = inode_change_ok(dentry->d_inode, iattr);
+       if (retval)
+               return retval;
+
+       p9attr.valid = iattr->ia_valid;
+       p9attr.mode = iattr->ia_mode;
+       p9attr.uid = iattr->ia_uid;
+       p9attr.gid = iattr->ia_gid;
+       p9attr.size = iattr->ia_size;
+       p9attr.atime_sec = iattr->ia_atime.tv_sec;
+       p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
+       p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
+       p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
+
+       retval = -EPERM;
+       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
+
+       retval = p9_client_setattr(fid, &p9attr);
+       if (retval >= 0)
+               retval = inode_setattr(dentry->d_inode, iattr);
+
+       return retval;
+}
+
 /**
  * v9fs_stat2inode - populate an inode structure with mistat info
  * @stat: Plan 9 metadata (mistat) structure
@@ -979,6 +1335,77 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
        inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
 }
 
+/**
+ * v9fs_stat2inode_dotl - populate an inode structure with stat info
+ * @stat: stat structure
+ * @inode: inode to populate
+ * @sb: superblock of filesystem
+ *
+ */
+
+void
+v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
+{
+
+       if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
+               inode->i_atime.tv_sec = stat->st_atime_sec;
+               inode->i_atime.tv_nsec = stat->st_atime_nsec;
+               inode->i_mtime.tv_sec = stat->st_mtime_sec;
+               inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
+               inode->i_ctime.tv_sec = stat->st_ctime_sec;
+               inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
+               inode->i_uid = stat->st_uid;
+               inode->i_gid = stat->st_gid;
+               inode->i_nlink = stat->st_nlink;
+               inode->i_mode = stat->st_mode;
+               inode->i_rdev = new_decode_dev(stat->st_rdev);
+
+               if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
+                       init_special_inode(inode, inode->i_mode, inode->i_rdev);
+
+               i_size_write(inode, stat->st_size);
+               inode->i_blocks = stat->st_blocks;
+       } else {
+               if (stat->st_result_mask & P9_STATS_ATIME) {
+                       inode->i_atime.tv_sec = stat->st_atime_sec;
+                       inode->i_atime.tv_nsec = stat->st_atime_nsec;
+               }
+               if (stat->st_result_mask & P9_STATS_MTIME) {
+                       inode->i_mtime.tv_sec = stat->st_mtime_sec;
+                       inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
+               }
+               if (stat->st_result_mask & P9_STATS_CTIME) {
+                       inode->i_ctime.tv_sec = stat->st_ctime_sec;
+                       inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
+               }
+               if (stat->st_result_mask & P9_STATS_UID)
+                       inode->i_uid = stat->st_uid;
+               if (stat->st_result_mask & P9_STATS_GID)
+                       inode->i_gid = stat->st_gid;
+               if (stat->st_result_mask & P9_STATS_NLINK)
+                       inode->i_nlink = stat->st_nlink;
+               if (stat->st_result_mask & P9_STATS_MODE) {
+                       inode->i_mode = stat->st_mode;
+                       if ((S_ISBLK(inode->i_mode)) ||
+                                               (S_ISCHR(inode->i_mode)))
+                               init_special_inode(inode, inode->i_mode,
+                                                               inode->i_rdev);
+               }
+               if (stat->st_result_mask & P9_STATS_RDEV)
+                       inode->i_rdev = new_decode_dev(stat->st_rdev);
+               if (stat->st_result_mask & P9_STATS_SIZE)
+                       i_size_write(inode, stat->st_size);
+               if (stat->st_result_mask & P9_STATS_BLOCKS)
+                       inode->i_blocks = stat->st_blocks;
+       }
+       if (stat->st_result_mask & P9_STATS_GEN)
+                       inode->i_generation = stat->st_gen;
+
+       /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
+        * because the inode structure does not have fields for them.
+        */
+}
+
 /**
  * v9fs_qid2ino - convert qid into inode number
  * @qid: qid to hash
@@ -1022,7 +1449,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        if (IS_ERR(fid))
                return PTR_ERR(fid);
 
-       if (!v9fs_proto_dotu(v9ses))
+       if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))
                return -EBADF;
 
        st = p9_client_stat(fid);
@@ -1127,6 +1554,99 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
        return 0;
 }
 
+/**
+ * v9fs_vfs_symlink_dotl - helper function to create symlinks
+ * @dir: directory inode containing symlink
+ * @dentry: dentry for symlink
+ * @symname: symlink data
+ *
+ * See Also: 9P2000.L RFC for more information
+ *
+ */
+
+static int
+v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
+               const char *symname)
+{
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *dfid;
+       struct p9_fid *fid = NULL;
+       struct inode *inode;
+       struct p9_qid qid;
+       char *name;
+       int err;
+       gid_t gid;
+
+       name = (char *) dentry->d_name.name;
+       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n",
+                       dir->i_ino, name, symname);
+       v9ses = v9fs_inode2v9ses(dir);
+
+       dfid = v9fs_fid_lookup(dentry->d_parent);
+       if (IS_ERR(dfid)) {
+               err = PTR_ERR(dfid);
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               return err;
+       }
+
+       gid = v9fs_get_fsgid_for_create(dir);
+
+       if (gid < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid);
+               goto error;
+       }
+
+       /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
+       err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
+
+       if (err < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
+               goto error;
+       }
+
+       if (v9ses->cache) {
+               /* Now walk from the parent so we can get an unopened fid. */
+               fid = p9_client_walk(dfid, 1, &name, 1);
+               if (IS_ERR(fid)) {
+                       err = PTR_ERR(fid);
+                       P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+                                       err);
+                       fid = NULL;
+                       goto error;
+               }
+
+               /* instantiate inode and assign the unopened fid to dentry */
+               inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+                                       err);
+                       goto error;
+               }
+               dentry->d_op = &v9fs_cached_dentry_operations;
+               d_instantiate(dentry, inode);
+               err = v9fs_fid_add(dentry, fid);
+               if (err < 0)
+                       goto error;
+               fid = NULL;
+       } else {
+               /* Not in cached mode. No need to populate inode with stat */
+               inode = v9fs_get_inode(dir->i_sb, S_IFLNK);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       goto error;
+               }
+               dentry->d_op = &v9fs_dentry_operations;
+               d_instantiate(dentry, inode);
+       }
+
+error:
+       if (fid)
+               p9_client_clunk(fid);
+
+       return err;
+}
+
 /**
  * v9fs_vfs_symlink - helper function to create symlinks
  * @dir: directory inode containing symlink
@@ -1185,6 +1705,76 @@ clunk_fid:
        return retval;
 }
 
+/**
+ * v9fs_vfs_link_dotl - create a hardlink for dotl
+ * @old_dentry: dentry for file to link to
+ * @dir: inode destination for new link
+ * @dentry: dentry for link
+ *
+ */
+
+static int
+v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
+               struct dentry *dentry)
+{
+       int err;
+       struct p9_fid *dfid, *oldfid;
+       char *name;
+       struct v9fs_session_info *v9ses;
+       struct dentry *dir_dentry;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
+                       dir->i_ino, old_dentry->d_name.name,
+                       dentry->d_name.name);
+
+       v9ses = v9fs_inode2v9ses(dir);
+       dir_dentry = v9fs_dentry_from_dir_inode(dir);
+       dfid = v9fs_fid_lookup(dir_dentry);
+       if (IS_ERR(dfid))
+               return PTR_ERR(dfid);
+
+       oldfid = v9fs_fid_lookup(old_dentry);
+       if (IS_ERR(oldfid))
+               return PTR_ERR(oldfid);
+
+       name = (char *) dentry->d_name.name;
+
+       err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name);
+
+       if (err < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
+               return err;
+       }
+
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+               /* Get the latest stat info from server. */
+               struct p9_fid *fid;
+               struct p9_stat_dotl *st;
+
+               fid = v9fs_fid_lookup(old_dentry);
+               if (IS_ERR(fid))
+                       return PTR_ERR(fid);
+
+               st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+               if (IS_ERR(st))
+                       return PTR_ERR(st);
+
+               v9fs_stat2inode_dotl(st, old_dentry->d_inode);
+
+               kfree(st);
+       } else {
+               /* Caching disabled. No need to get upto date stat info.
+                * This dentry will be released immediately. So, just i_count++
+                */
+               atomic_inc(&old_dentry->d_inode->i_count);
+       }
+
+       dentry->d_op = old_dentry->d_op;
+       d_instantiate(dentry, old_dentry->d_inode);
+
+       return err;
+}
+
 /**
  * v9fs_vfs_mknod - create a special file
  * @dir: inode destination for new link
@@ -1230,6 +1820,100 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
        return retval;
 }
 
+/**
+ * v9fs_vfs_mknod_dotl - create a special file
+ * @dir: inode destination for new link
+ * @dentry: dentry for file
+ * @mode: mode for creation
+ * @rdev: device associated with special file
+ *
+ */
+static int
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
+               dev_t rdev)
+{
+       int err;
+       char *name;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid = NULL, *dfid = NULL;
+       struct inode *inode;
+       gid_t gid;
+       struct p9_qid qid;
+       struct dentry *dir_dentry;
+
+       P9_DPRINTK(P9_DEBUG_VFS,
+               " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
+               dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
+
+       if (!new_valid_dev(rdev))
+               return -EINVAL;
+
+       v9ses = v9fs_inode2v9ses(dir);
+       dir_dentry = v9fs_dentry_from_dir_inode(dir);
+       dfid = v9fs_fid_lookup(dir_dentry);
+       if (IS_ERR(dfid)) {
+               err = PTR_ERR(dfid);
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               dfid = NULL;
+               goto error;
+       }
+
+       gid = v9fs_get_fsgid_for_create(dir);
+       if (gid < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+               goto error;
+       }
+
+       name = (char *) dentry->d_name.name;
+
+       err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
+       if (err < 0)
+               goto error;
+
+       /* instantiate inode and assign the unopened fid to the dentry */
+       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+               fid = p9_client_walk(dfid, 1, &name, 1);
+               if (IS_ERR(fid)) {
+                       err = PTR_ERR(fid);
+                       P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+                               err);
+                       fid = NULL;
+                       goto error;
+               }
+
+               inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+                               err);
+                       goto error;
+               }
+               dentry->d_op = &v9fs_cached_dentry_operations;
+               d_instantiate(dentry, inode);
+               err = v9fs_fid_add(dentry, fid);
+               if (err < 0)
+                       goto error;
+               fid = NULL;
+       } else {
+               /*
+                * Not in cached mode. No need to populate inode with stat.
+                * socket syscall returns a fd, so we need instantiate
+                */
+               inode = v9fs_get_inode(dir->i_sb, mode);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       goto error;
+               }
+               dentry->d_op = &v9fs_dentry_operations;
+               d_instantiate(dentry, inode);
+       }
+
+error:
+       if (fid)
+               p9_client_clunk(fid);
+       return err;
+}
+
 static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
@@ -1238,24 +1922,29 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .unlink = v9fs_vfs_unlink,
        .mkdir = v9fs_vfs_mkdir,
        .rmdir = v9fs_vfs_rmdir,
-       .mknod = v9fs_vfs_mknod,
+       .mknod = v9fs_vfs_mknod_dotl,
        .rename = v9fs_vfs_rename,
        .getattr = v9fs_vfs_getattr,
        .setattr = v9fs_vfs_setattr,
 };
 
 static const struct inode_operations v9fs_dir_inode_operations_dotl = {
-       .create = v9fs_vfs_create,
+       .create = v9fs_vfs_create_dotl,
        .lookup = v9fs_vfs_lookup,
-       .symlink = v9fs_vfs_symlink,
-       .link = v9fs_vfs_link,
+       .link = v9fs_vfs_link_dotl,
+       .symlink = v9fs_vfs_symlink_dotl,
        .unlink = v9fs_vfs_unlink,
-       .mkdir = v9fs_vfs_mkdir,
+       .mkdir = v9fs_vfs_mkdir_dotl,
        .rmdir = v9fs_vfs_rmdir,
-       .mknod = v9fs_vfs_mknod,
+       .mknod = v9fs_vfs_mknod_dotl,
        .rename = v9fs_vfs_rename,
-       .getattr = v9fs_vfs_getattr,
-       .setattr = v9fs_vfs_setattr,
+       .getattr = v9fs_vfs_getattr_dotl,
+       .setattr = v9fs_vfs_setattr_dotl,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = v9fs_listxattr,
+
 };
 
 static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1276,8 +1965,12 @@ static const struct inode_operations v9fs_file_inode_operations = {
 };
 
 static const struct inode_operations v9fs_file_inode_operations_dotl = {
-       .getattr = v9fs_vfs_getattr,
-       .setattr = v9fs_vfs_setattr,
+       .getattr = v9fs_vfs_getattr_dotl,
+       .setattr = v9fs_vfs_setattr_dotl,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = v9fs_listxattr,
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations = {
@@ -1292,6 +1985,10 @@ static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
        .readlink = generic_readlink,
        .follow_link = v9fs_vfs_follow_link,
        .put_link = v9fs_vfs_put_link,
-       .getattr = v9fs_vfs_getattr,
-       .setattr = v9fs_vfs_setattr,
+       .getattr = v9fs_vfs_getattr_dotl,
+       .setattr = v9fs_vfs_setattr_dotl,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = v9fs_listxattr,
 };
index be74d020436e2d7badad70f6e89e430d12f9d6e8..4b9ede0b41b71f94fb1ae00031c7b5417cf37683 100644 (file)
@@ -45,6 +45,7 @@
 #include "v9fs.h"
 #include "v9fs_vfs.h"
 #include "fid.h"
+#include "xattr.h"
 
 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
 
@@ -77,9 +78,10 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
        sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
        sb->s_blocksize = 1 << sb->s_blocksize_bits;
        sb->s_magic = V9FS_MAGIC;
-       if (v9fs_proto_dotl(v9ses))
+       if (v9fs_proto_dotl(v9ses)) {
                sb->s_op = &v9fs_super_ops_dotl;
-       else
+               sb->s_xattr = v9fs_xattr_handlers;
+       } else
                sb->s_op = &v9fs_super_ops;
        sb->s_bdi = &v9ses->bdi;
 
@@ -107,7 +109,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
        struct inode *inode = NULL;
        struct dentry *root = NULL;
        struct v9fs_session_info *v9ses = NULL;
-       struct p9_wstat *st = NULL;
        int mode = S_IRWXUGO | S_ISVTX;
        struct p9_fid *fid;
        int retval = 0;
@@ -124,16 +125,10 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
                goto close_session;
        }
 
-       st = p9_client_stat(fid);
-       if (IS_ERR(st)) {
-               retval = PTR_ERR(st);
-               goto clunk_fid;
-       }
-
        sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
        if (IS_ERR(sb)) {
                retval = PTR_ERR(sb);
-               goto free_stat;
+               goto clunk_fid;
        }
        v9fs_fill_super(sb, v9ses, flags, data);
 
@@ -151,22 +146,38 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
        }
 
        sb->s_root = root;
-       root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
 
-       v9fs_stat2inode(st, root->d_inode, sb);
+       if (v9fs_proto_dotl(v9ses)) {
+               struct p9_stat_dotl *st = NULL;
+               st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+               if (IS_ERR(st)) {
+                       retval = PTR_ERR(st);
+                       goto clunk_fid;
+               }
+
+               v9fs_stat2inode_dotl(st, root->d_inode);
+               kfree(st);
+       } else {
+               struct p9_wstat *st = NULL;
+               st = p9_client_stat(fid);
+               if (IS_ERR(st)) {
+                       retval = PTR_ERR(st);
+                       goto clunk_fid;
+               }
+
+               root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
+               v9fs_stat2inode(st, root->d_inode, sb);
+
+               p9stat_free(st);
+               kfree(st);
+       }
 
        v9fs_fid_add(root, fid);
-       p9stat_free(st);
-       kfree(st);
 
 P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
        simple_set_mnt(mnt, sb);
        return 0;
 
-free_stat:
-       p9stat_free(st);
-       kfree(st);
-
 clunk_fid:
        p9_client_clunk(fid);
 
@@ -176,8 +187,6 @@ close_session:
        return retval;
 
 release_sb:
-       p9stat_free(st);
-       kfree(st);
        deactivate_locked_super(sb);
        return retval;
 }
@@ -278,4 +287,5 @@ struct file_system_type v9fs_fs_type = {
        .get_sb = v9fs_get_sb,
        .kill_sb = v9fs_kill_super,
        .owner = THIS_MODULE,
+       .fs_flags = FS_RENAME_DOES_D_MOVE,
 };
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
new file mode 100644 (file)
index 0000000..f88e5c2
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
+
+#include "fid.h"
+#include "xattr.h"
+
+/*
+ * v9fs_xattr_get()
+ *
+ * Copy an extended attribute into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+ * Returns a negative error number on failure, or the number of bytes
+ * used / required on success.
+ */
+ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
+                      void *buffer, size_t buffer_size)
+{
+       ssize_t retval;
+       int msize, read_count;
+       u64 offset = 0, attr_size;
+       struct p9_fid *fid, *attr_fid;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
+               __func__, name, buffer_size);
+
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
+
+       attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
+       if (IS_ERR(attr_fid)) {
+               retval = PTR_ERR(attr_fid);
+               P9_DPRINTK(P9_DEBUG_VFS,
+                       "p9_client_attrwalk failed %zd\n", retval);
+               attr_fid = NULL;
+               goto error;
+       }
+       if (!buffer_size) {
+               /* request to get the attr_size */
+               retval = attr_size;
+               goto error;
+       }
+       if (attr_size > buffer_size) {
+               retval = -ERANGE;
+               goto error;
+       }
+       msize = attr_fid->clnt->msize;
+       while (attr_size) {
+               if (attr_size > (msize - P9_IOHDRSZ))
+                       read_count = msize - P9_IOHDRSZ;
+               else
+                       read_count = attr_size;
+               read_count = p9_client_read(attr_fid, ((char *)buffer)+offset,
+                                       NULL, offset, read_count);
+               if (read_count < 0) {
+                       /* error in xattr read */
+                       retval = read_count;
+                       goto error;
+               }
+               offset += read_count;
+               attr_size -= read_count;
+       }
+       /* Total read xattr bytes */
+       retval = offset;
+error:
+       if (attr_fid)
+               p9_client_clunk(attr_fid);
+       return retval;
+
+}
+
+/*
+ * v9fs_xattr_set()
+ *
+ * Create, replace or remove an extended attribute for this inode. Buffer
+ * is NULL to remove an existing extended attribute, and non-NULL to
+ * either replace an existing extended attribute, or create a new extended
+ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
+ * specify that an extended attribute must exist and must not exist
+ * previous to the call, respectively.
+ *
+ * Returns 0, or a negative error number on failure.
+ */
+int v9fs_xattr_set(struct dentry *dentry, const char *name,
+                  const void *value, size_t value_len, int flags)
+{
+       u64 offset = 0;
+       int retval, msize, write_count;
+       struct p9_fid *fid = NULL;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu flags = %d\n",
+               __func__, name, value_len, flags);
+
+       fid = v9fs_fid_clone(dentry);
+       if (IS_ERR(fid)) {
+               retval = PTR_ERR(fid);
+               fid = NULL;
+               goto error;
+       }
+       /*
+        * On success fid points to xattr
+        */
+       retval = p9_client_xattrcreate(fid, name, value_len, flags);
+       if (retval < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS,
+                       "p9_client_xattrcreate failed %d\n", retval);
+               goto error;
+       }
+       msize = fid->clnt->msize;;
+       while (value_len) {
+               if (value_len > (msize - P9_IOHDRSZ))
+                       write_count = msize - P9_IOHDRSZ;
+               else
+                       write_count = value_len;
+               write_count = p9_client_write(fid, ((char *)value)+offset,
+                                       NULL, offset, write_count);
+               if (write_count < 0) {
+                       /* error in xattr write */
+                       retval = write_count;
+                       goto error;
+               }
+               offset += write_count;
+               value_len -= write_count;
+       }
+       /* Total read xattr bytes */
+       retval = offset;
+error:
+       if (fid)
+               retval = p9_client_clunk(fid);
+       return retval;
+}
+
+ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+{
+       return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
+}
+
+const struct xattr_handler *v9fs_xattr_handlers[] = {
+       &v9fs_xattr_user_handler,
+       NULL
+};
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
new file mode 100644 (file)
index 0000000..9ddf672
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef FS_9P_XATTR_H
+#define FS_9P_XATTR_H
+
+#include <linux/xattr.h>
+
+extern const struct xattr_handler *v9fs_xattr_handlers[];
+extern struct xattr_handler v9fs_xattr_user_handler;
+
+extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
+                             void *, size_t);
+extern int v9fs_xattr_set(struct dentry *, const char *,
+                         const void *, size_t, int);
+extern ssize_t v9fs_listxattr(struct dentry *, char *, size_t);
+#endif /* FS_9P_XATTR_H */
diff --git a/fs/9p/xattr_user.c b/fs/9p/xattr_user.c
new file mode 100644 (file)
index 0000000..d0b701b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "xattr.h"
+
+static int v9fs_xattr_user_get(struct dentry *dentry, const char *name,
+                       void *buffer, size_t size, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_USER_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
+       memcpy(full_name+prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_get(dentry, full_name, buffer, size);
+       kfree(full_name);
+       return retval;
+}
+
+static int v9fs_xattr_user_set(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_USER_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
+       memcpy(full_name + prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
+       kfree(full_name);
+       return retval;
+}
+
+struct xattr_handler v9fs_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .get    = v9fs_xattr_user_get,
+       .set    = v9fs_xattr_user_set,
+};
index 80f352596807a43f08235209d0434998a8ae07a6..5739fd7f88b4996698f6768f8aa9b955177d127a 100644 (file)
@@ -131,6 +131,15 @@ config CIFS_DFS_UPCALL
            IP addresses) which is needed for implicit mounts of DFS junction
            points. If unsure, say N.
 
+config CIFS_FSCACHE
+         bool "Provide CIFS client caching support (EXPERIMENTAL)"
+         depends on EXPERIMENTAL
+         depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
+         help
+           Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
+           to be cached locally on disk through the general filesystem cache
+           manager. If unsure, say N.
+
 config CIFS_EXPERIMENTAL
          bool "CIFS Experimental Features (EXPERIMENTAL)"
          depends on CIFS && EXPERIMENTAL
index 9948c0030e86df5ad020785341f514b814fed5ee..adefa60a9bdc10108ec9c802e4cbe1ea26f3f6e0 100644 (file)
@@ -11,3 +11,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
 
 cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
+
+cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c
new file mode 100644 (file)
index 0000000..224d7bb
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ *   fs/cifs/cache.c - CIFS filesystem cache index structure definitions
+ *
+ *   Copyright (c) 2010 Novell, Inc.
+ *   Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "fscache.h"
+#include "cifs_debug.h"
+
+/*
+ * CIFS filesystem definition for FS-Cache
+ */
+struct fscache_netfs cifs_fscache_netfs = {
+       .name = "cifs",
+       .version = 0,
+};
+
+/*
+ * Register CIFS for caching with FS-Cache
+ */
+int cifs_fscache_register(void)
+{
+       return fscache_register_netfs(&cifs_fscache_netfs);
+}
+
+/*
+ * Unregister CIFS for caching
+ */
+void cifs_fscache_unregister(void)
+{
+       fscache_unregister_netfs(&cifs_fscache_netfs);
+}
+
+/*
+ * Key layout of CIFS server cache index object
+ */
+struct cifs_server_key {
+       uint16_t        family;         /* address family */
+       uint16_t        port;           /* IP port */
+       union {
+               struct in_addr  ipv4_addr;
+               struct in6_addr ipv6_addr;
+       } addr[0];
+};
+
+/*
+ * Server object keyed by {IPaddress,port,family} tuple
+ */
+static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
+                                  void *buffer, uint16_t maxbuf)
+{
+       const struct TCP_Server_Info *server = cookie_netfs_data;
+       const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr;
+       struct cifs_server_key *key = buffer;
+       uint16_t key_len = sizeof(struct cifs_server_key);
+
+       memset(key, 0, key_len);
+
+       /*
+        * Should not be a problem as sin_family/sin6_family overlays
+        * sa_family field
+        */
+       switch (sa->sa_family) {
+       case AF_INET:
+               key->family = server->addr.sockAddr.sin_family;
+               key->port = server->addr.sockAddr.sin_port;
+               key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr;
+               key_len += sizeof(key->addr[0].ipv4_addr);
+               break;
+
+       case AF_INET6:
+               key->family = server->addr.sockAddr6.sin6_family;
+               key->port = server->addr.sockAddr6.sin6_port;
+               key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr;
+               key_len += sizeof(key->addr[0].ipv6_addr);
+               break;
+
+       default:
+               cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family);
+               key_len = 0;
+               break;
+       }
+
+       return key_len;
+}
+
+/*
+ * Server object for FS-Cache
+ */
+const struct fscache_cookie_def cifs_fscache_server_index_def = {
+       .name = "CIFS.server",
+       .type = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key = cifs_server_get_key,
+};
+
+/*
+ * Auxiliary data attached to CIFS superblock within the cache
+ */
+struct cifs_fscache_super_auxdata {
+       u64     resource_id;            /* unique server resource id */
+};
+
+static char *extract_sharename(const char *treename)
+{
+       const char *src;
+       char *delim, *dst;
+       int len;
+
+       /* skip double chars at the beginning */
+       src = treename + 2;
+
+       /* share name is always preceded by '\\' now */
+       delim = strchr(src, '\\');
+       if (!delim)
+               return ERR_PTR(-EINVAL);
+       delim++;
+       len = strlen(delim);
+
+       /* caller has to free the memory */
+       dst = kstrndup(delim, len, GFP_KERNEL);
+       if (!dst)
+               return ERR_PTR(-ENOMEM);
+
+       return dst;
+}
+
+/*
+ * Superblock object currently keyed by share name
+ */
+static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer,
+                                  uint16_t maxbuf)
+{
+       const struct cifsTconInfo *tcon = cookie_netfs_data;
+       char *sharename;
+       uint16_t len;
+
+       sharename = extract_sharename(tcon->treeName);
+       if (IS_ERR(sharename)) {
+               cFYI(1, "CIFS: couldn't extract sharename\n");
+               sharename = NULL;
+               return 0;
+       }
+
+       len = strlen(sharename);
+       if (len > maxbuf)
+               return 0;
+
+       memcpy(buffer, sharename, len);
+
+       kfree(sharename);
+
+       return len;
+}
+
+static uint16_t
+cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer,
+                          uint16_t maxbuf)
+{
+       struct cifs_fscache_super_auxdata auxdata;
+       const struct cifsTconInfo *tcon = cookie_netfs_data;
+
+       memset(&auxdata, 0, sizeof(auxdata));
+       auxdata.resource_id = tcon->resource_id;
+
+       if (maxbuf > sizeof(auxdata))
+               maxbuf = sizeof(auxdata);
+
+       memcpy(buffer, &auxdata, maxbuf);
+
+       return maxbuf;
+}
+
+static enum
+fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
+                                             const void *data,
+                                             uint16_t datalen)
+{
+       struct cifs_fscache_super_auxdata auxdata;
+       const struct cifsTconInfo *tcon = cookie_netfs_data;
+
+       if (datalen != sizeof(auxdata))
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       memset(&auxdata, 0, sizeof(auxdata));
+       auxdata.resource_id = tcon->resource_id;
+
+       if (memcmp(data, &auxdata, datalen) != 0)
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       return FSCACHE_CHECKAUX_OKAY;
+}
+
+/*
+ * Superblock object for FS-Cache
+ */
+const struct fscache_cookie_def cifs_fscache_super_index_def = {
+       .name = "CIFS.super",
+       .type = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key = cifs_super_get_key,
+       .get_aux = cifs_fscache_super_get_aux,
+       .check_aux = cifs_fscache_super_check_aux,
+};
+
+/*
+ * Auxiliary data attached to CIFS inode within the cache
+ */
+struct cifs_fscache_inode_auxdata {
+       struct timespec last_write_time;
+       struct timespec last_change_time;
+       u64             eof;
+};
+
+static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data,
+                                          void *buffer, uint16_t maxbuf)
+{
+       const struct cifsInodeInfo *cifsi = cookie_netfs_data;
+       uint16_t keylen;
+
+       /* use the UniqueId as the key */
+       keylen = sizeof(cifsi->uniqueid);
+       if (keylen > maxbuf)
+               keylen = 0;
+       else
+               memcpy(buffer, &cifsi->uniqueid, keylen);
+
+       return keylen;
+}
+
+static void
+cifs_fscache_inode_get_attr(const void *cookie_netfs_data, uint64_t *size)
+{
+       const struct cifsInodeInfo *cifsi = cookie_netfs_data;
+
+       *size = cifsi->vfs_inode.i_size;
+}
+
+static uint16_t
+cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer,
+                          uint16_t maxbuf)
+{
+       struct cifs_fscache_inode_auxdata auxdata;
+       const struct cifsInodeInfo *cifsi = cookie_netfs_data;
+
+       memset(&auxdata, 0, sizeof(auxdata));
+       auxdata.eof = cifsi->server_eof;
+       auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
+       auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+
+       if (maxbuf > sizeof(auxdata))
+               maxbuf = sizeof(auxdata);
+
+       memcpy(buffer, &auxdata, maxbuf);
+
+       return maxbuf;
+}
+
+static enum
+fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
+                                             const void *data,
+                                             uint16_t datalen)
+{
+       struct cifs_fscache_inode_auxdata auxdata;
+       struct cifsInodeInfo *cifsi = cookie_netfs_data;
+
+       if (datalen != sizeof(auxdata))
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       memset(&auxdata, 0, sizeof(auxdata));
+       auxdata.eof = cifsi->server_eof;
+       auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
+       auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+
+       if (memcmp(data, &auxdata, datalen) != 0)
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       return FSCACHE_CHECKAUX_OKAY;
+}
+
+static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data)
+{
+       struct cifsInodeInfo *cifsi = cookie_netfs_data;
+       struct pagevec pvec;
+       pgoff_t first;
+       int loop, nr_pages;
+
+       pagevec_init(&pvec, 0);
+       first = 0;
+
+       cFYI(1, "cifs inode 0x%p now uncached", cifsi);
+
+       for (;;) {
+               nr_pages = pagevec_lookup(&pvec,
+                                         cifsi->vfs_inode.i_mapping, first,
+                                         PAGEVEC_SIZE - pagevec_count(&pvec));
+               if (!nr_pages)
+                       break;
+
+               for (loop = 0; loop < nr_pages; loop++)
+                       ClearPageFsCache(pvec.pages[loop]);
+
+               first = pvec.pages[nr_pages - 1]->index + 1;
+
+               pvec.nr = nr_pages;
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+}
+
+const struct fscache_cookie_def cifs_fscache_inode_object_def = {
+       .name           = "CIFS.uniqueid",
+       .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
+       .get_key        = cifs_fscache_inode_get_key,
+       .get_attr       = cifs_fscache_inode_get_attr,
+       .get_aux        = cifs_fscache_inode_get_aux,
+       .check_aux      = cifs_fscache_inode_check_aux,
+       .now_uncached   = cifs_fscache_inode_now_uncached,
+};
index ac19a6f3dae079c3b1caa34d0157e3536e609ba8..dc1ed50ea06e2ad7b23e7a547e793b1f48718b21 100644 (file)
@@ -230,28 +230,22 @@ compose_mount_options_err:
        goto compose_mount_options_out;
 }
 
-
-static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
-               struct dentry *dentry, const struct dfs_info3_param *ref)
+/**
+ * cifs_dfs_do_refmount - mounts specified path using provided refferal
+ * @cifs_sb:           parent/root superblock
+ * @fullpath:          full path in UNC format
+ * @ref:               server's referral
+ */
+static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
+               const char *fullpath, const struct dfs_info3_param *ref)
 {
-       struct cifs_sb_info *cifs_sb;
        struct vfsmount *mnt;
        char *mountdata;
        char *devname = NULL;
-       char *fullpath;
-
-       cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-       /*
-        * this function gives us a path with a double backslash prefix. We
-        * require a single backslash for DFS.
-        */
-       fullpath = build_path_from_dentry(dentry);
-       if (!fullpath)
-               return ERR_PTR(-ENOMEM);
 
+       /* strip first '\' from fullpath */
        mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
                        fullpath + 1, ref, &devname);
-       kfree(fullpath);
 
        if (IS_ERR(mountdata))
                return (struct vfsmount *)mountdata;
@@ -357,8 +351,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
                        rc = -EINVAL;
                        goto out_err;
                }
-               mnt = cifs_dfs_do_refmount(nd->path.mnt,
-                               nd->path.dentry, referrals + i);
+               mnt = cifs_dfs_do_refmount(cifs_sb,
+                               full_path, referrals + i);
                cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
                                        referrals[i].node_name, mnt);
 
index 246a167cb91354e39455e11dacd84b25f22ec0a9..9e771450c3b8eba5230ffa16c30cb95a73151868 100644 (file)
@@ -35,6 +35,7 @@
 #define CIFS_MOUNT_DYNPERM      0x1000 /* allow in-memory only mode setting   */
 #define CIFS_MOUNT_NOPOSIXBRL   0x2000 /* mandatory not posix byte range lock */
 #define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
+#define CIFS_MOUNT_FSCACHE     0x8000 /* local caching enabled */
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
index 379bd7d9c05f8ade3045f6c19a17f81b089c7a5a..6effccff85a50d742c23122ea155087c63191909 100644 (file)
@@ -143,6 +143,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
        dp = description + strlen(description);
        sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
 
+       dp = description + strlen(description);
+       sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
+
        dp = description + strlen(description);
        sprintf(dp, ";user=%s", sesInfo->userName);
 
index 2cb1a70214d7298070266840bb97ad7bf2c98a57..8a2cf129e535a21a8cd8bf7bc9116e2bbbd025da 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/key-type.h>
 #include "dns_resolve.h"
 #include "cifs_spnego.h"
+#include "fscache.h"
 #define CIFS_MAGIC_NUMBER 0xFF534D42   /* the first four bytes of SMB PDUs */
 
 int cifsFYI = 0;
@@ -328,6 +329,12 @@ cifs_destroy_inode(struct inode *inode)
        kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
 }
 
+static void
+cifs_clear_inode(struct inode *inode)
+{
+       cifs_fscache_release_inode_cookie(inode);
+}
+
 static void
 cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
 {
@@ -489,6 +496,7 @@ static const struct super_operations cifs_super_ops = {
        .alloc_inode = cifs_alloc_inode,
        .destroy_inode = cifs_destroy_inode,
        .drop_inode     = cifs_drop_inode,
+       .clear_inode    = cifs_clear_inode,
 /*     .delete_inode   = cifs_delete_inode,  */  /* Do not need above
        function unless later we add lazy close of inodes or unless the
        kernel forgets to call us with the same number of releases (closes)
@@ -902,6 +910,10 @@ init_cifs(void)
                cFYI(1, "cifs_max_pending set to max of 256");
        }
 
+       rc = cifs_fscache_register();
+       if (rc)
+               goto out;
+
        rc = cifs_init_inodecache();
        if (rc)
                goto out_clean_proc;
@@ -951,6 +963,8 @@ init_cifs(void)
        cifs_destroy_inodecache();
  out_clean_proc:
        cifs_proc_clean();
+       cifs_fscache_unregister();
+ out:
        return rc;
 }
 
@@ -959,6 +973,7 @@ exit_cifs(void)
 {
        cFYI(DBG2, "exit_cifs");
        cifs_proc_clean();
+       cifs_fscache_unregister();
 #ifdef CONFIG_CIFS_DFS_UPCALL
        cifs_dfs_release_automount_timer();
        cifs_exit_dns_resolver();
index a7eb65c84b1c16725110b8732163968bc9caef24..d82f5fb4761e252511028b7380e78509c4b7f50a 100644 (file)
@@ -114,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.64"
+#define CIFS_VERSION   "1.65"
 #endif                         /* _CIFSFS_H */
index a88479ceaad59602919d3d6d1a1c7a01855d69ac..59906146ad3634e89eb403530d2d592e3ac0216b 100644 (file)
@@ -16,6 +16,9 @@
  *   the GNU Lesser General Public License for more details.
  *
  */
+#ifndef _CIFS_GLOB_H
+#define _CIFS_GLOB_H
+
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/slab.h>
@@ -34,7 +37,7 @@
 #define MAX_SHARE_SIZE  64     /* used to be 20, this should still be enough */
 #define MAX_USERNAME_SIZE 32   /* 32 is to allow for 15 char names + null
                                   termination then *2 for unicode versions */
-#define MAX_PASSWORD_SIZE 16
+#define MAX_PASSWORD_SIZE 512  /* max for windows seems to be 256 wide chars */
 
 #define CIFS_MIN_RCV_POOL 4
 
@@ -80,8 +83,7 @@ enum statusEnum {
 };
 
 enum securityEnum {
-       PLAINTXT = 0,           /* Legacy with Plaintext passwords */
-       LANMAN,                 /* Legacy LANMAN auth */
+       LANMAN = 0,                     /* Legacy LANMAN auth */
        NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO, NTLMv2 hash */
@@ -142,7 +144,6 @@ struct TCP_Server_Info {
        struct list_head pending_mid_q;
        void *Server_NlsInfo;   /* BB - placeholder for future NLS info  */
        unsigned short server_codepage; /* codepage for the server    */
-       unsigned long ip_address;       /* IP addr for the server if known */
        enum protocolEnum protocolType;
        char versionMajor;
        char versionMinor;
@@ -190,19 +191,9 @@ struct TCP_Server_Info {
        bool    sec_mskerberos;         /* supports legacy MS Kerberos */
        bool    sec_kerberosu2u;        /* supports U2U Kerberos */
        bool    sec_ntlmssp;            /* supports NTLMSSP */
-};
-
-/*
- * The following is our shortcut to user information.  We surface the uid,
- * and name. We always get the password on the fly in case it
- * has changed. We also hang a list of sessions owned by this user off here.
- */
-struct cifsUidInfo {
-       struct list_head userList;
-       struct list_head sessionList; /* SMB sessions for this user */
-       uid_t linux_uid;
-       char user[MAX_USERNAME_SIZE + 1];       /* ascii name of user */
-       /* BB may need ptr or callback for PAM or WinBind info */
+#ifdef CONFIG_CIFS_FSCACHE
+       struct fscache_cookie   *fscache; /* client index cache cookie */
+#endif
 };
 
 /*
@@ -212,9 +203,6 @@ struct cifsSesInfo {
        struct list_head smb_ses_list;
        struct list_head tcon_list;
        struct mutex session_mutex;
-#if 0
-       struct cifsUidInfo *uidInfo;    /* pointer to user info */
-#endif
        struct TCP_Server_Info *server; /* pointer to server info */
        int ses_count;          /* reference counter */
        enum statusEnum status;
@@ -226,7 +214,8 @@ struct cifsSesInfo {
        char *serverNOS;        /* name of network operating system of server */
        char *serverDomain;     /* security realm of server */
        int Suid;               /* remote smb uid  */
-       uid_t linux_uid;        /* local Linux uid */
+       uid_t linux_uid;        /* overriding owner of files on the mount */
+       uid_t cred_uid;         /* owner of credentials */
        int capabilities;
        char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
                                TCP names - will ipv6 and sctp addresses fit? */
@@ -311,6 +300,10 @@ struct cifsTconInfo {
        bool local_lease:1; /* check leases (only) on local system not remote */
        bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
        bool need_reconnect:1; /* connection reset, tid now invalid */
+#ifdef CONFIG_CIFS_FSCACHE
+       u64 resource_id;                /* server resource id */
+       struct fscache_cookie *fscache; /* cookie for share */
+#endif
        /* BB add field for back pointer to sb struct(s)? */
 };
 
@@ -398,6 +391,9 @@ struct cifsInodeInfo {
        bool invalid_mapping:1;         /* pagecache is invalid */
        u64  server_eof;                /* current file size on server */
        u64  uniqueid;                  /* server inode number */
+#ifdef CONFIG_CIFS_FSCACHE
+       struct fscache_cookie *fscache;
+#endif
        struct inode vfs_inode;
 };
 
@@ -733,3 +729,5 @@ GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
 GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
 
 extern const struct slow_work_ops cifs_oplock_break_ops;
+
+#endif /* _CIFS_GLOB_H */
index fb6318b81509801a218d8a2248542e427b9516ce..2eaebbd31132f8118d3afb347433eca50846e417 100644 (file)
@@ -86,7 +86,9 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        struct TCP_Server_Info *server);
-extern int cifs_convert_address(char *src, void *dst);
+extern int cifs_convert_address(struct sockaddr *dst, char *src);
+extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src,
+                               unsigned short int port);
 extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
                            const struct cifsTconInfo *, int /* length of
index 2208f06e4c45ec17d1908b5435ee556be54d6dbe..2a43a0aca965424bf0fb66234560e3a1fbabb08a 100644 (file)
@@ -48,6 +48,7 @@
 #include "nterr.h"
 #include "rfc1002pdu.h"
 #include "cn_cifs.h"
+#include "fscache.h"
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
@@ -66,6 +67,7 @@ struct smb_vol {
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[16]; /* netbios name of client */
        char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
+       uid_t cred_uid;
        uid_t linux_uid;
        gid_t linux_gid;
        mode_t file_mode;
@@ -97,6 +99,7 @@ struct smb_vol {
        bool noblocksnd:1;
        bool noautotune:1;
        bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
+       bool fsc:1;     /* enable fscache */
        unsigned int rsize;
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
@@ -830,7 +833,8 @@ cifs_parse_mount_options(char *options, const char *devname,
        /* null target name indicates to use *SMBSERVR default called name
           if we end up sending RFC1001 session initialize */
        vol->target_rfc1001_name[0] = 0;
-       vol->linux_uid = current_uid();  /* use current_euid() instead? */
+       vol->cred_uid = current_uid();
+       vol->linux_uid = current_uid();
        vol->linux_gid = current_gid();
 
        /* default to only allowing write access to owner of the mount */
@@ -1257,6 +1261,12 @@ cifs_parse_mount_options(char *options, const char *devname,
                } else if ((strnicmp(data, "nocase", 6) == 0) ||
                           (strnicmp(data, "ignorecase", 10)  == 0)) {
                        vol->nocase = 1;
+               } else if (strnicmp(data, "mand", 4) == 0) {
+                       /* ignore */
+               } else if (strnicmp(data, "nomand", 6) == 0) {
+                       /* ignore */
+               } else if (strnicmp(data, "_netdev", 7) == 0) {
+                       /* ignore */
                } else if (strnicmp(data, "brl", 3) == 0) {
                        vol->nobrl =  0;
                } else if ((strnicmp(data, "nobrl", 5) == 0) ||
@@ -1331,6 +1341,8 @@ cifs_parse_mount_options(char *options, const char *devname,
                        printk(KERN_WARNING "CIFS: Mount option noac not "
                                "supported. Instead set "
                                "/proc/fs/cifs/LookupCacheEnabled to 0\n");
+               } else if (strnicmp(data, "fsc", 3) == 0) {
+                       vol->fsc = true;
                } else
                        printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
                                                data);
@@ -1380,18 +1392,92 @@ cifs_parse_mount_options(char *options, const char *devname,
        return 0;
 }
 
+static bool
+match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
+{
+       struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+
+       switch (addr->sa_family) {
+       case AF_INET:
+               if (addr4->sin_addr.s_addr !=
+                   server->addr.sockAddr.sin_addr.s_addr)
+                       return false;
+               if (addr4->sin_port &&
+                   addr4->sin_port != server->addr.sockAddr.sin_port)
+                       return false;
+               break;
+       case AF_INET6:
+               if (!ipv6_addr_equal(&addr6->sin6_addr,
+                                    &server->addr.sockAddr6.sin6_addr))
+                       return false;
+               if (addr6->sin6_scope_id !=
+                   server->addr.sockAddr6.sin6_scope_id)
+                       return false;
+               if (addr6->sin6_port &&
+                   addr6->sin6_port != server->addr.sockAddr6.sin6_port)
+                       return false;
+               break;
+       }
+
+       return true;
+}
+
+static bool
+match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
+{
+       unsigned int secFlags;
+
+       if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+               secFlags = vol->secFlg;
+       else
+               secFlags = global_secflags | vol->secFlg;
+
+       switch (server->secType) {
+       case LANMAN:
+               if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
+                       return false;
+               break;
+       case NTLMv2:
+               if (!(secFlags & CIFSSEC_MAY_NTLMV2))
+                       return false;
+               break;
+       case NTLM:
+               if (!(secFlags & CIFSSEC_MAY_NTLM))
+                       return false;
+               break;
+       case Kerberos:
+               if (!(secFlags & CIFSSEC_MAY_KRB5))
+                       return false;
+               break;
+       case RawNTLMSSP:
+               if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
+                       return false;
+               break;
+       default:
+               /* shouldn't happen */
+               return false;
+       }
+
+       /* now check if signing mode is acceptible */
+       if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
+           (server->secMode & SECMODE_SIGN_REQUIRED))
+                       return false;
+       else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
+                (server->secMode &
+                 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
+                       return false;
+
+       return true;
+}
+
 static struct TCP_Server_Info *
-cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port)
+cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 {
-       struct list_head *tmp;
        struct TCP_Server_Info *server;
-       struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
-       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
 
        write_lock(&cifs_tcp_ses_lock);
-       list_for_each(tmp, &cifs_tcp_ses_list) {
-               server = list_entry(tmp, struct TCP_Server_Info,
-                                   tcp_ses_list);
+       list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
                /*
                 * the demux thread can exit on its own while still in CifsNew
                 * so don't accept any sockets in that state. Since the
@@ -1401,37 +1487,11 @@ cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port)
                if (server->tcpStatus == CifsNew)
                        continue;
 
-               switch (addr->ss_family) {
-               case AF_INET:
-                       if (addr4->sin_addr.s_addr ==
-                           server->addr.sockAddr.sin_addr.s_addr) {
-                               addr4->sin_port = htons(port);
-                               /* user overrode default port? */
-                               if (addr4->sin_port) {
-                                       if (addr4->sin_port !=
-                                           server->addr.sockAddr.sin_port)
-                                               continue;
-                               }
-                               break;
-                       } else
-                               continue;
+               if (!match_address(server, addr))
+                       continue;
 
-               case AF_INET6:
-                       if (ipv6_addr_equal(&addr6->sin6_addr,
-                           &server->addr.sockAddr6.sin6_addr) &&
-                           (addr6->sin6_scope_id ==
-                           server->addr.sockAddr6.sin6_scope_id)) {
-                               addr6->sin6_port = htons(port);
-                               /* user overrode default port? */
-                               if (addr6->sin6_port) {
-                                       if (addr6->sin6_port !=
-                                          server->addr.sockAddr6.sin6_port)
-                                               continue;
-                               }
-                               break;
-                       } else
-                               continue;
-               }
+               if (!match_security(server, vol))
+                       continue;
 
                ++server->srv_count;
                write_unlock(&cifs_tcp_ses_lock);
@@ -1460,6 +1520,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
        server->tcpStatus = CifsExiting;
        spin_unlock(&GlobalMid_Lock);
 
+       cifs_fscache_release_client_cookie(server);
+
        task = xchg(&server->tsk, NULL);
        if (task)
                force_sig(SIGKILL, task);
@@ -1479,7 +1541,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip);
 
        if (volume_info->UNCip && volume_info->UNC) {
-               rc = cifs_convert_address(volume_info->UNCip, &addr);
+               rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
+                                       volume_info->UNCip,
+                                       volume_info->port);
                if (!rc) {
                        /* we failed translating address */
                        rc = -EINVAL;
@@ -1499,7 +1563,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        }
 
        /* see if we already have a matching tcp_ses */
-       tcp_ses = cifs_find_tcp_session(&addr, volume_info->port);
+       tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info);
        if (tcp_ses)
                return tcp_ses;
 
@@ -1543,12 +1607,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                cFYI(1, "attempting ipv6 connect");
                /* BB should we allow ipv6 on port 139? */
                /* other OS never observed in Wild doing 139 with v6 */
-               sin_server6->sin6_port = htons(volume_info->port);
                memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
                        sizeof(struct sockaddr_in6));
                rc = ipv6_connect(tcp_ses);
        } else {
-               sin_server->sin_port = htons(volume_info->port);
                memcpy(&tcp_ses->addr.sockAddr, sin_server,
                        sizeof(struct sockaddr_in));
                rc = ipv4_connect(tcp_ses);
@@ -1577,6 +1639,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
        write_unlock(&cifs_tcp_ses_lock);
 
+       cifs_fscache_get_client_cookie(tcp_ses);
+
        return tcp_ses;
 
 out_err:
@@ -1591,17 +1655,27 @@ out_err:
 }
 
 static struct cifsSesInfo *
-cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
+cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
-       struct list_head *tmp;
        struct cifsSesInfo *ses;
 
        write_lock(&cifs_tcp_ses_lock);
-       list_for_each(tmp, &server->smb_ses_list) {
-               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
-               if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
-                       continue;
-
+       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+               switch (server->secType) {
+               case Kerberos:
+                       if (vol->cred_uid != ses->cred_uid)
+                               continue;
+                       break;
+               default:
+                       /* anything else takes username/password */
+                       if (strncmp(ses->userName, vol->username,
+                                   MAX_USERNAME_SIZE))
+                               continue;
+                       if (strlen(vol->username) != 0 &&
+                           strncmp(ses->password, vol->password,
+                                   MAX_PASSWORD_SIZE))
+                               continue;
+               }
                ++ses->ses_count;
                write_unlock(&cifs_tcp_ses_lock);
                return ses;
@@ -1643,7 +1717,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 
        xid = GetXid();
 
-       ses = cifs_find_smb_ses(server, volume_info->username);
+       ses = cifs_find_smb_ses(server, volume_info);
        if (ses) {
                cFYI(1, "Existing smb sess found (status=%d)", ses->status);
 
@@ -1706,6 +1780,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
                if (ses->domainName)
                        strcpy(ses->domainName, volume_info->domainname);
        }
+       ses->cred_uid = volume_info->cred_uid;
        ses->linux_uid = volume_info->linux_uid;
        ses->overrideSecFlg = volume_info->secFlg;
 
@@ -1773,6 +1848,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
        CIFSSMBTDis(xid, tcon);
        _FreeXid(xid);
 
+       cifs_fscache_release_super_cookie(tcon);
        tconInfoFree(tcon);
        cifs_put_smb_ses(ses);
 }
@@ -1843,6 +1919,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
        list_add(&tcon->tcon_list, &ses->tcon_list);
        write_unlock(&cifs_tcp_ses_lock);
 
+       cifs_fscache_get_super_cookie(tcon);
+
        return tcon;
 
 out_fail:
@@ -2397,6 +2475,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
        if (pvolume_info->dynperm)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+       if (pvolume_info->fsc)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
        if (pvolume_info->direct_io) {
                cFYI(1, "mounting share using direct i/o");
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
index e7ae78b66fa15b89162b18a12d76c90f48b8b508..a7de5e9fff11f166b23dd472149277bf059c50fa 100644 (file)
@@ -130,12 +130,6 @@ cifs_bp_rename_retry:
        return full_path;
 }
 
-/*
- * When called with struct file pointer set to NULL, there is no way we could
- * update file->private_data, but getting it stuck on openFileList provides a
- * way to access it from cifs_fill_filedata and thereby set file->private_data
- * from cifs_open.
- */
 struct cifsFileInfo *
 cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
                  struct file *file, struct vfsmount *mnt, unsigned int oflags)
index 49315cbf742d7ab22876b69349b6441723d850b7..3ad7f4300c45049ad7384a2251203dfe2f30c087 100644 (file)
@@ -44,7 +44,7 @@ is_ip(char *name)
 {
        struct sockaddr_storage ss;
 
-       return cifs_convert_address(name, &ss);
+       return cifs_convert_address((struct sockaddr *)&ss, name);
 }
 
 static int
@@ -227,7 +227,7 @@ failed_put_cred:
        return ret;
 }
 
-void __exit cifs_exit_dns_resolver(void)
+void cifs_exit_dns_resolver(void)
 {
        key_revoke(dns_resolver_cache->thread_keyring);
        unregister_key_type(&key_type_dns_resolver);
index 26b9eaa9f5ee5898ae4241412e4127512fc95ec4..5d7f291df162731bb58abc124242211a88c0ad37 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifdef __KERNEL__
 extern int __init cifs_init_dns_resolver(void);
-extern void __exit cifs_exit_dns_resolver(void);
+extern void cifs_exit_dns_resolver(void);
 extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
 #endif /* KERNEL */
 
index 409e4f523e61e56aae0e1b892c2a9021ebe3728d..fa04a00d126dc5787850f905e195b41d7b310b5c 100644 (file)
@@ -40,6 +40,7 @@
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "fscache.h"
 
 static inline int cifs_convert_flags(unsigned int flags)
 {
@@ -282,6 +283,9 @@ int cifs_open(struct inode *inode, struct file *file)
                                CIFSSMBClose(xid, tcon, netfid);
                                rc = -ENOMEM;
                        }
+
+                       cifs_fscache_set_inode_cookie(inode, file);
+
                        goto out;
                } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                        if (tcon->ses->serverNOS)
@@ -373,6 +377,8 @@ int cifs_open(struct inode *inode, struct file *file)
                goto out;
        }
 
+       cifs_fscache_set_inode_cookie(inode, file);
+
        if (oplock & CIFS_CREATE_ACTION) {
                /* time to set mode which we can not set earlier due to
                   problems creating new read-only files */
@@ -427,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        __u16 netfid;
 
        if (file->private_data)
-               pCifsFile = (struct cifsFileInfo *)file->private_data;
+               pCifsFile = file->private_data;
        else
                return -EBADF;
 
@@ -565,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file)
        int xid, timeout;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
-       struct cifsFileInfo *pSMBFile =
-               (struct cifsFileInfo *)file->private_data;
+       struct cifsFileInfo *pSMBFile = file->private_data;
 
        xid = GetXid();
 
@@ -641,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
 {
        int rc = 0;
        int xid;
-       struct cifsFileInfo *pCFileStruct =
-           (struct cifsFileInfo *)file->private_data;
+       struct cifsFileInfo *pCFileStruct = file->private_data;
        char *ptmp;
 
        cFYI(1, "Closedir inode = 0x%p", inode);
@@ -863,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                                      length, pfLock,
                                      posix_lock_type, wait_flag);
        } else {
-               struct cifsFileInfo *fid =
-                       (struct cifsFileInfo *)file->private_data;
+               struct cifsFileInfo *fid = file->private_data;
 
                if (numLock) {
                        rc = CIFSSMBLock(xid, tcon, netfid, length,
@@ -965,7 +968,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
        if (file->private_data == NULL)
                return -EBADF;
-       open_file = (struct cifsFileInfo *) file->private_data;
+       open_file = file->private_data;
 
        rc = generic_write_checks(file, poffset, &write_size, 0);
        if (rc)
@@ -1067,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
        if (file->private_data == NULL)
                return -EBADF;
-       open_file = (struct cifsFileInfo *)file->private_data;
+       open_file = file->private_data;
 
        xid = GetXid();
 
@@ -1651,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync)
        int xid;
        int rc = 0;
        struct cifsTconInfo *tcon;
-       struct cifsFileInfo *smbfile =
-               (struct cifsFileInfo *)file->private_data;
+       struct cifsFileInfo *smbfile = file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
 
        xid = GetXid();
@@ -1756,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                FreeXid(xid);
                return rc;
        }
-       open_file = (struct cifsFileInfo *)file->private_data;
+       open_file = file->private_data;
 
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, "attempting read on write only file instance");
@@ -1837,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                FreeXid(xid);
                return rc;
        }
-       open_file = (struct cifsFileInfo *)file->private_data;
+       open_file = file->private_data;
 
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, "attempting read on write only file instance");
@@ -1942,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
                SetPageUptodate(page);
                unlock_page(page);
                data += PAGE_CACHE_SIZE;
+
+               /* add page to FS-Cache */
+               cifs_readpage_to_fscache(mapping->host, page);
        }
        return;
 }
@@ -1968,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                FreeXid(xid);
                return rc;
        }
-       open_file = (struct cifsFileInfo *)file->private_data;
+       open_file = file->private_data;
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        pTcon = cifs_sb->tcon;
 
+       /*
+        * Reads as many pages as possible from fscache. Returns -ENOBUFS
+        * immediately if the cookie is negative
+        */
+       rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
+                                        &num_pages);
+       if (rc == 0)
+               goto read_complete;
+
        cFYI(DBG2, "rpages: num pages %d", num_pages);
        for (i = 0; i < num_pages; ) {
                unsigned contig_pages;
@@ -2082,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                smb_read_data = NULL;
        }
 
+read_complete:
        FreeXid(xid);
        return rc;
 }
@@ -2092,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
        char *read_data;
        int rc;
 
+       /* Is the page cached? */
+       rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
+       if (rc == 0)
+               goto read_complete;
+
        page_cache_get(page);
        read_data = kmap(page);
        /* for reads over a certain size could initiate async read ahead */
@@ -2111,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
 
        flush_dcache_page(page);
        SetPageUptodate(page);
+
+       /* send this page to the cache */
+       cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
+
        rc = 0;
 
 io_error:
        kunmap(page);
        page_cache_release(page);
+
+read_complete:
        return rc;
 }
 
@@ -2265,6 +2291,22 @@ out:
        return rc;
 }
 
+static int cifs_release_page(struct page *page, gfp_t gfp)
+{
+       if (PagePrivate(page))
+               return 0;
+
+       return cifs_fscache_release_page(page, gfp);
+}
+
+static void cifs_invalidate_page(struct page *page, unsigned long offset)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
+
+       if (offset == 0)
+               cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
+}
+
 static void
 cifs_oplock_break(struct slow_work *work)
 {
@@ -2338,6 +2380,8 @@ const struct address_space_operations cifs_addr_ops = {
        .write_begin = cifs_write_begin,
        .write_end = cifs_write_end,
        .set_page_dirty = __set_page_dirty_nobuffers,
+       .releasepage = cifs_release_page,
+       .invalidatepage = cifs_invalidate_page,
        /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
@@ -2354,6 +2398,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
        .write_begin = cifs_write_begin,
        .write_end = cifs_write_end,
        .set_page_dirty = __set_page_dirty_nobuffers,
+       .releasepage = cifs_release_page,
+       .invalidatepage = cifs_invalidate_page,
        /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c
new file mode 100644 (file)
index 0000000..9f3f5c4
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ *   fs/cifs/fscache.c - CIFS filesystem cache interface
+ *
+ *   Copyright (c) 2010 Novell, Inc.
+ *   Author(s): Suresh Jayaraman (sjayaraman@suse.de>
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "fscache.h"
+#include "cifsglob.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
+{
+       server->fscache =
+               fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
+                               &cifs_fscache_server_index_def, server);
+       cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server,
+                               server->fscache);
+}
+
+void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
+{
+       cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server,
+                               server->fscache);
+       fscache_relinquish_cookie(server->fscache, 0);
+       server->fscache = NULL;
+}
+
+void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon)
+{
+       struct TCP_Server_Info *server = tcon->ses->server;
+
+       tcon->fscache =
+               fscache_acquire_cookie(server->fscache,
+                               &cifs_fscache_super_index_def, tcon);
+       cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)",
+                               server->fscache, tcon->fscache);
+}
+
+void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon)
+{
+       cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache);
+       fscache_relinquish_cookie(tcon->fscache, 0);
+       tcon->fscache = NULL;
+}
+
+static void cifs_fscache_enable_inode_cookie(struct inode *inode)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+
+       if (cifsi->fscache)
+               return;
+
+       cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
+                               &cifs_fscache_inode_object_def,
+                               cifsi);
+       cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)",
+                       cifs_sb->tcon->fscache, cifsi->fscache);
+}
+
+void cifs_fscache_release_inode_cookie(struct inode *inode)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+       if (cifsi->fscache) {
+               cFYI(1, "CIFS releasing inode cookie (0x%p)",
+                               cifsi->fscache);
+               fscache_relinquish_cookie(cifsi->fscache, 0);
+               cifsi->fscache = NULL;
+       }
+}
+
+static void cifs_fscache_disable_inode_cookie(struct inode *inode)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+       if (cifsi->fscache) {
+               cFYI(1, "CIFS disabling inode cookie (0x%p)",
+                               cifsi->fscache);
+               fscache_relinquish_cookie(cifsi->fscache, 1);
+               cifsi->fscache = NULL;
+       }
+}
+
+void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
+{
+       if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+               cifs_fscache_disable_inode_cookie(inode);
+       else {
+               cifs_fscache_enable_inode_cookie(inode);
+               cFYI(1, "CIFS: fscache inode cookie set");
+       }
+}
+
+void cifs_fscache_reset_inode_cookie(struct inode *inode)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct fscache_cookie *old = cifsi->fscache;
+
+       if (cifsi->fscache) {
+               /* retire the current fscache cache and get a new one */
+               fscache_relinquish_cookie(cifsi->fscache, 1);
+
+               cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
+                                       &cifs_fscache_inode_object_def,
+                                       cifsi);
+               cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p",
+                               cifsi->fscache, old);
+       }
+}
+
+int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       if (PageFsCache(page)) {
+               struct inode *inode = page->mapping->host;
+               struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+               cFYI(1, "CIFS: fscache release page (0x%p/0x%p)",
+                               page, cifsi->fscache);
+               if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
+                                               int error)
+{
+       cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)",
+                       page, error);
+       if (!error)
+               SetPageUptodate(page);
+       unlock_page(page);
+}
+
+/*
+ * Retrieve a page from FS-Cache
+ */
+int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+       int ret;
+
+       cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p",
+                       CIFS_I(inode)->fscache, page, inode);
+       ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
+                                        cifs_readpage_from_fscache_complete,
+                                        NULL,
+                                        GFP_KERNEL);
+       switch (ret) {
+
+       case 0: /* page found in fscache, read submitted */
+               cFYI(1, "CIFS: readpage_from_fscache: submitted");
+               return ret;
+       case -ENOBUFS:  /* page won't be cached */
+       case -ENODATA:  /* page not in cache */
+               cFYI(1, "CIFS: readpage_from_fscache %d", ret);
+               return 1;
+
+       default:
+               cERROR(1, "unknown error ret = %d", ret);
+       }
+       return ret;
+}
+
+/*
+ * Retrieve a set of pages from FS-Cache
+ */
+int __cifs_readpages_from_fscache(struct inode *inode,
+                               struct address_space *mapping,
+                               struct list_head *pages,
+                               unsigned *nr_pages)
+{
+       int ret;
+
+       cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)",
+                       CIFS_I(inode)->fscache, *nr_pages, inode);
+       ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
+                                         pages, nr_pages,
+                                         cifs_readpage_from_fscache_complete,
+                                         NULL,
+                                         mapping_gfp_mask(mapping));
+       switch (ret) {
+       case 0: /* read submitted to the cache for all pages */
+               cFYI(1, "CIFS: readpages_from_fscache: submitted");
+               return ret;
+
+       case -ENOBUFS:  /* some pages are not cached and can't be */
+       case -ENODATA:  /* some pages are not cached */
+               cFYI(1, "CIFS: readpages_from_fscache: no page");
+               return 1;
+
+       default:
+               cFYI(1, "unknown error ret = %d", ret);
+       }
+
+       return ret;
+}
+
+void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+{
+       int ret;
+
+       cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p",
+                       CIFS_I(inode)->fscache, page, inode);
+       ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL);
+       if (ret != 0)
+               fscache_uncache_page(CIFS_I(inode)->fscache, page);
+}
+
+void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct fscache_cookie *cookie = cifsi->fscache;
+
+       cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie);
+       fscache_wait_on_page_write(cookie, page);
+       fscache_uncache_page(cookie, page);
+}
+
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h
new file mode 100644 (file)
index 0000000..31b88ec
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *   fs/cifs/fscache.h - CIFS filesystem cache interface definitions
+ *
+ *   Copyright (c) 2010 Novell, Inc.
+ *   Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _CIFS_FSCACHE_H
+#define _CIFS_FSCACHE_H
+
+#include <linux/fscache.h>
+
+#include "cifsglob.h"
+
+#ifdef CONFIG_CIFS_FSCACHE
+
+extern struct fscache_netfs cifs_fscache_netfs;
+extern const struct fscache_cookie_def cifs_fscache_server_index_def;
+extern const struct fscache_cookie_def cifs_fscache_super_index_def;
+extern const struct fscache_cookie_def cifs_fscache_inode_object_def;
+
+extern int cifs_fscache_register(void);
+extern void cifs_fscache_unregister(void);
+
+/*
+ * fscache.c
+ */
+extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *);
+extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
+extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *);
+extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *);
+
+extern void cifs_fscache_release_inode_cookie(struct inode *);
+extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
+extern void cifs_fscache_reset_inode_cookie(struct inode *);
+
+extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
+extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
+extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
+extern int __cifs_readpages_from_fscache(struct inode *,
+                                        struct address_space *,
+                                        struct list_head *,
+                                        unsigned *);
+
+extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
+
+static inline void cifs_fscache_invalidate_page(struct page *page,
+                                              struct inode *inode)
+{
+       if (PageFsCache(page))
+               __cifs_fscache_invalidate_page(page, inode);
+}
+
+static inline int cifs_readpage_from_fscache(struct inode *inode,
+                                            struct page *page)
+{
+       if (CIFS_I(inode)->fscache)
+               return __cifs_readpage_from_fscache(inode, page);
+
+       return -ENOBUFS;
+}
+
+static inline int cifs_readpages_from_fscache(struct inode *inode,
+                                             struct address_space *mapping,
+                                             struct list_head *pages,
+                                             unsigned *nr_pages)
+{
+       if (CIFS_I(inode)->fscache)
+               return __cifs_readpages_from_fscache(inode, mapping, pages,
+                                                    nr_pages);
+       return -ENOBUFS;
+}
+
+static inline void cifs_readpage_to_fscache(struct inode *inode,
+                                           struct page *page)
+{
+       if (PageFsCache(page))
+               __cifs_readpage_to_fscache(inode, page);
+}
+
+#else /* CONFIG_CIFS_FSCACHE */
+static inline int cifs_fscache_register(void) { return 0; }
+static inline void cifs_fscache_unregister(void) {}
+
+static inline void
+cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {}
+static inline void
+cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {}
+static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {}
+static inline void
+cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {}
+
+static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
+static inline void cifs_fscache_set_inode_cookie(struct inode *inode,
+                                                struct file *filp) {}
+static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {}
+static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       return 1; /* May release page */
+}
+
+static inline void cifs_fscache_invalidate_page(struct page *page,
+                       struct inode *inode) {}
+static inline int
+cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+       return -ENOBUFS;
+}
+
+static inline int cifs_readpages_from_fscache(struct inode *inode,
+                                             struct address_space *mapping,
+                                             struct list_head *pages,
+                                             unsigned *nr_pages)
+{
+       return -ENOBUFS;
+}
+
+static inline void cifs_readpage_to_fscache(struct inode *inode,
+                       struct page *page) {}
+
+#endif /* CONFIG_CIFS_FSCACHE */
+
+#endif /* _CIFS_FSCACHE_H */
index 6f0683c689523894cb6fae3edd79181876084d42..a15b3a9bbff40af95532b152a5bbf993a44bac99 100644 (file)
@@ -29,6 +29,7 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "fscache.h"
 
 
 static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
@@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp)
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsTconInfo *tcon = cifs_sb->tcon;
-       struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+       struct cifsFileInfo *cfile = filp->private_data;
 
        xid = GetXid();
        rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp)
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsTconInfo *tcon = cifs_sb->tcon;
-       struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+       struct cifsFileInfo *cfile = filp->private_data;
 
        xid = GetXid();
        rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -723,9 +724,14 @@ cifs_find_inode(struct inode *inode, void *opaque)
 {
        struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
 
+       /* don't match inode with different uniqueid */
        if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
                return 0;
 
+       /* don't match inode of different type */
+       if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
+               return 0;
+
        /*
         * uh oh -- it's a directory. We can't use it since hardlinked dirs are
         * verboten. Disable serverino and return it as if it were found, the
@@ -776,6 +782,10 @@ retry_iget5_locked:
                        inode->i_flags |= S_NOATIME | S_NOCMTIME;
                if (inode->i_state & I_NEW) {
                        inode->i_ino = hash;
+#ifdef CONFIG_CIFS_FSCACHE
+                       /* initialize per-inode cache cookie pointer */
+                       CIFS_I(inode)->fscache = NULL;
+#endif
                        unlock_new_inode(inode);
                }
        }
@@ -807,6 +817,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
+#ifdef CONFIG_CIFS_FSCACHE
+       /* populate tcon->resource_id */
+       cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid;
+#endif
+
        if (rc && cifs_sb->tcon->ipc) {
                cFYI(1, "ipc connection - fake read inode");
                inode->i_mode |= S_IFDIR;
@@ -1568,6 +1583,7 @@ cifs_invalidate_mapping(struct inode *inode)
                        cifs_i->write_behind_rc = rc;
        }
        invalidate_remote_inode(inode);
+       cifs_fscache_reset_inode_cookie(inode);
 }
 
 int cifs_revalidate_file(struct file *filp)
index 505926f1ee6b99d9f3388fb2bb8208dc1f498758..9d38a71c8e1449561f625d5762c2337714d31563 100644 (file)
@@ -41,8 +41,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
        __u64   ExtAttrMask = 0;
        __u64   caps;
        struct cifsTconInfo *tcon;
-       struct cifsFileInfo *pSMBFile =
-               (struct cifsFileInfo *)filep->private_data;
+       struct cifsFileInfo *pSMBFile = filep->private_data;
 #endif /* CONFIG_CIFS_POSIX */
 
        xid = GetXid();
index d35d52889cb54a57e62b99b6e6d6e31e4cb19dd0..c6721ee26dbcb77aca9acf528efb1226de9eebea 100644 (file)
@@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
        {ERRremcd, -EACCES},
        {ERRdiffdevice, -EXDEV},
        {ERRnofiles, -ENOENT},
+       {ERRwriteprot, -EROFS},
        {ERRbadshare, -ETXTBSY},
        {ERRlock, -EACCES},
        {ERRunsup, -EINVAL},
@@ -164,7 +165,7 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
  * Returns 0 on failure.
  */
 int
-cifs_convert_address(char *src, void *dst)
+cifs_convert_address(struct sockaddr *dst, char *src)
 {
        int rc;
        char *pct, *endp;
@@ -201,6 +202,27 @@ cifs_convert_address(char *src, void *dst)
        return rc;
 }
 
+int
+cifs_fill_sockaddr(struct sockaddr *dst, char *src,
+                  const unsigned short int port)
+{
+       if (!cifs_convert_address(dst, src))
+               return 0;
+
+       switch (dst->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)dst)->sin_port = htons(port);
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)dst)->sin6_port = htons(port);
+               break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
 /*****************************************************************************
 convert a NT status code to a dos class/code
  *****************************************************************************/
index daf1753af674584e2f83f5c1c974da7762097801..d5e591fab4753bf48bde4e9d7883f1051d2dc280 100644 (file)
@@ -847,6 +847,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 
                tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
+               if (tmp_buf == NULL) {
+                       rc = -ENOMEM;
+                       break;
+               }
+
                for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
                        if (current_entry == NULL) {
                                /* evaluate whether this case is an error */
index c5084d27db7c10ab28dd6e8903d8f8d201046c2b..7f16cb825fe59d654639177dac63ec5382bf361c 100644 (file)
@@ -76,6 +76,7 @@
 #define ERRnofiles             18      /* A File Search command can find no
                                           more files matching the specified
                                           criteria. */
+#define ERRwriteprot           19      /* media is write protected */
 #define ERRgeneral             31
 #define ERRbadshare            32      /* The sharing mode specified for an
                                           Open conflicts with existing FIDs on
index 7600aacf531dc8ed16ccfb727878d13834a16503..a10cb91cadea04ac68ff5ce0db34d6d07bdd6371 100644 (file)
@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio)
  * filesystems can use it to hold additional state between get_block calls and
  * dio_complete.
  */
-static int dio_complete(struct dio *dio, loff_t offset, int ret)
+static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async)
 {
        ssize_t transferred = 0;
 
@@ -239,14 +239,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret)
                        transferred = dio->i_size - offset;
        }
 
-       if (dio->end_io && dio->result)
-               dio->end_io(dio->iocb, offset, transferred,
-                           dio->map_bh.b_private);
-
-       if (dio->flags & DIO_LOCKING)
-               /* lockdep: non-owner release */
-               up_read_non_owner(&dio->inode->i_alloc_sem);
-
        if (ret == 0)
                ret = dio->page_errors;
        if (ret == 0)
@@ -254,6 +246,17 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret)
        if (ret == 0)
                ret = transferred;
 
+       if (dio->end_io && dio->result) {
+               dio->end_io(dio->iocb, offset, transferred,
+                           dio->map_bh.b_private, ret, is_async);
+       } else if (is_async) {
+               aio_complete(dio->iocb, ret, 0);
+       }
+
+       if (dio->flags & DIO_LOCKING)
+               /* lockdep: non-owner release */
+               up_read_non_owner(&dio->inode->i_alloc_sem);
+
        return ret;
 }
 
@@ -277,8 +280,7 @@ static void dio_bio_end_aio(struct bio *bio, int error)
        spin_unlock_irqrestore(&dio->bio_lock, flags);
 
        if (remaining == 0) {
-               int ret = dio_complete(dio, dio->iocb->ki_pos, 0);
-               aio_complete(dio->iocb, ret, 0);
+               dio_complete(dio, dio->iocb->ki_pos, 0, true);
                kfree(dio);
        }
 }
@@ -1126,7 +1128,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        spin_unlock_irqrestore(&dio->bio_lock, flags);
 
        if (ret2 == 0) {
-               ret = dio_complete(dio, offset, ret);
+               ret = dio_complete(dio, offset, ret, false);
                kfree(dio);
        } else
                BUG_ON(ret != -EIOCBQUEUED);
index 42272d67955a413cdd17a53980fe5dac410cceff..0afc8c1d8cf3597bf075ecb731a16accb67687ad 100644 (file)
@@ -3775,7 +3775,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags)
 }
 
 static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
-                           ssize_t size, void *private)
+                           ssize_t size, void *private, int ret,
+                           bool is_async)
 {
         ext4_io_end_t *io_end = iocb->private;
        struct workqueue_struct *wq;
@@ -3784,7 +3785,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
 
        /* if not async direct IO or dio with 0 bytes write, just return */
        if (!io_end || !size)
-               return;
+               goto out;
 
        ext_debug("ext4_end_io_dio(): io_end 0x%p"
                  "for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
@@ -3795,7 +3796,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
        if (io_end->flag != EXT4_IO_UNWRITTEN){
                ext4_free_io_end(io_end);
                iocb->private = NULL;
-               return;
+               goto out;
        }
 
        io_end->offset = offset;
@@ -3812,6 +3813,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
        list_add_tail(&io_end->list, &ei->i_completed_io_list);
        spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
        iocb->private = NULL;
+out:
+       if (is_async)
+               aio_complete(iocb, ret, 0);
 }
 
 static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
index 3cdc5f78a406357a7e4bcbffe5783facd35c7236..431be0795b6bdf27c43ca34a093c52ca127a77af 100644 (file)
@@ -1016,7 +1016,7 @@ static int fuse_permission(struct inode *inode, int mask)
                   exist.  So if permissions are revoked this won't be
                   noticed immediately, only after the attribute
                   timeout has expired */
-       } else if (mask & MAY_ACCESS) {
+       } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
                err = fuse_access(inode, mask);
        } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                if (!(inode->i_mode & S_IXUGO)) {
index 9f8b52500d63551c4111370bc59b357cb177f60a..5e96cbd8a454a532c058a0880fec8a6b38571ddf 100644 (file)
@@ -136,10 +136,7 @@ static int gfs2_writeback_writepage(struct page *page,
        if (ret <= 0)
                return ret;
 
-       ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
-       if (ret == -EAGAIN)
-               ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
-       return ret;
+       return nobh_writepage(page, gfs2_get_block_noalloc, wbc);
 }
 
 /**
@@ -637,9 +634,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
                }
        }
 
-       error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
-       if (error)
-               goto out_unlock;
+       alloc_required = gfs2_write_alloc_required(ip, pos, len);
 
        if (alloc_required || gfs2_is_jdata(ip))
                gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
index 84da64b551b2c1170f4e68550ead612ed6fd7b41..6f482809d1a35b4787e9cb62357958d532aeaa30 100644 (file)
@@ -1040,7 +1040,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
                goto out;
 
        if (gfs2_is_stuffed(ip)) {
-               u64 dsize = size + sizeof(struct gfs2_inode);
+               u64 dsize = size + sizeof(struct gfs2_dinode);
                ip->i_disksize = size;
                ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
@@ -1244,13 +1244,12 @@ int gfs2_file_dealloc(struct gfs2_inode *ip)
  * @ip: the file being written to
  * @offset: the offset to write to
  * @len: the number of bytes being written
- * @alloc_required: set to 1 if an alloc is required, 0 otherwise
  *
- * Returns: errno
+ * Returns: 1 if an alloc is required, 0 otherwise
  */
 
 int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
-                             unsigned int len, int *alloc_required)
+                             unsigned int len)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct buffer_head bh;
@@ -1258,26 +1257,23 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
        u64 lblock, lblock_stop, size;
        u64 end_of_file;
 
-       *alloc_required = 0;
-
        if (!len)
                return 0;
 
        if (gfs2_is_stuffed(ip)) {
                if (offset + len >
                    sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
-                       *alloc_required = 1;
+                       return 1;
                return 0;
        }
 
-       *alloc_required = 1;
        shift = sdp->sd_sb.sb_bsize_shift;
        BUG_ON(gfs2_is_dir(ip));
        end_of_file = (ip->i_disksize + sdp->sd_sb.sb_bsize - 1) >> shift;
        lblock = offset >> shift;
        lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
        if (lblock_stop > end_of_file)
-               return 0;
+               return 1;
 
        size = (lblock_stop - lblock) << shift;
        do {
@@ -1285,12 +1281,11 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
                bh.b_size = size;
                gfs2_block_map(&ip->i_inode, lblock, &bh, 0);
                if (!buffer_mapped(&bh))
-                       return 0;
+                       return 1;
                size -= bh.b_size;
                lblock += (bh.b_size >> ip->i_inode.i_blkbits);
        } while(size > 0);
 
-       *alloc_required = 0;
        return 0;
 }
 
index c983177e05ac2401887115781891c9a50f0972ba..a20a5213135a50ae9293da676eb533e9c04063db 100644 (file)
@@ -52,6 +52,6 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
 int gfs2_truncatei_resume(struct gfs2_inode *ip);
 int gfs2_file_dealloc(struct gfs2_inode *ip);
 int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
-                             unsigned int len, int *alloc_required);
+                             unsigned int len);
 
 #endif /* __BMAP_DOT_H__ */
index 6b48d7c268b24b65fae281e606fa32080490cf78..b9dd88a78dd47073e3af1645a1e0fa3bcb94d1bb 100644 (file)
@@ -955,7 +955,12 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
        /* Change the pointers.
           Don't bother distinguishing stuffed from non-stuffed.
           This code is complicated enough already. */
-       lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS | __GFP_NOFAIL);
+       lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS);
+       if (!lp) {
+               error = -ENOMEM;
+               goto fail_brelse;
+       }
+
        /*  Change the pointers  */
        for (x = 0; x < half_len; x++)
                lp[x] = cpu_to_be64(bn);
@@ -1063,7 +1068,9 @@ static int dir_double_exhash(struct gfs2_inode *dip)
 
        /*  Allocate both the "from" and "to" buffers in one big chunk  */
 
-       buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS | __GFP_NOFAIL);
+       buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS);
+       if (!buf)
+               return -ENOMEM;
 
        for (block = dip->i_disksize >> sdp->sd_hash_bsize_shift; block--;) {
                error = gfs2_dir_read_data(dip, (char *)buf,
index ed9a94f0ef159c369b6bd3a3598e1cd4d42fb697..4edd662c8232b2c24d1f1767b937f258071f8211 100644 (file)
@@ -351,7 +351,6 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        unsigned long last_index;
        u64 pos = page->index << PAGE_CACHE_SHIFT;
        unsigned int data_blocks, ind_blocks, rblocks;
-       int alloc_required = 0;
        struct gfs2_holder gh;
        struct gfs2_alloc *al;
        int ret;
@@ -364,8 +363,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
        set_bit(GIF_SW_PAGED, &ip->i_flags);
 
-       ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
-       if (ret || !alloc_required)
+       if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE))
                goto out_unlock;
        ret = -ENOMEM;
        al = gfs2_alloc_get(ip);
index 0898f3ec8212e5599df8c547d7d106aeb15d6c86..9adf8f924e08991c32d12938702e570f163c3215 100644 (file)
@@ -327,6 +327,30 @@ static void gfs2_holder_wake(struct gfs2_holder *gh)
        wake_up_bit(&gh->gh_iflags, HIF_WAIT);
 }
 
+/**
+ * do_error - Something unexpected has happened during a lock request
+ *
+ */
+
+static inline void do_error(struct gfs2_glock *gl, const int ret)
+{
+       struct gfs2_holder *gh, *tmp;
+
+       list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
+               if (test_bit(HIF_HOLDER, &gh->gh_iflags))
+                       continue;
+               if (ret & LM_OUT_ERROR)
+                       gh->gh_error = -EIO;
+               else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
+                       gh->gh_error = GLR_TRYFAILED;
+               else
+                       continue;
+               list_del_init(&gh->gh_list);
+               trace_gfs2_glock_queue(gh, 0);
+               gfs2_holder_wake(gh);
+       }
+}
+
 /**
  * do_promote - promote as many requests as possible on the current queue
  * @gl: The glock
@@ -375,35 +399,12 @@ restart:
                }
                if (gh->gh_list.prev == &gl->gl_holders)
                        return 1;
+               do_error(gl, 0);
                break;
        }
        return 0;
 }
 
-/**
- * do_error - Something unexpected has happened during a lock request
- *
- */
-
-static inline void do_error(struct gfs2_glock *gl, const int ret)
-{
-       struct gfs2_holder *gh, *tmp;
-
-       list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
-               if (test_bit(HIF_HOLDER, &gh->gh_iflags))
-                       continue;
-               if (ret & LM_OUT_ERROR)
-                       gh->gh_error = -EIO;
-               else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
-                       gh->gh_error = GLR_TRYFAILED;
-               else
-                       continue;
-               list_del_init(&gh->gh_list);
-               trace_gfs2_glock_queue(gh, 0);
-               gfs2_holder_wake(gh);
-       }
-}
-
 /**
  * find_first_waiter - find the first gh that's waiting for the glock
  * @gl: the glock
@@ -706,18 +707,8 @@ static void glock_work_func(struct work_struct *work)
 {
        unsigned long delay = 0;
        struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
-       struct gfs2_holder *gh;
        int drop_ref = 0;
 
-       if (unlikely(test_bit(GLF_FROZEN, &gl->gl_flags))) {
-               spin_lock(&gl->gl_spin);
-               gh = find_first_waiter(gl);
-               if (gh && (gh->gh_flags & LM_FLAG_NOEXP) &&
-                   test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
-                       set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
-               spin_unlock(&gl->gl_spin);
-       }
-
        if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) {
                finish_xmote(gl, gl->gl_reply);
                drop_ref = 1;
@@ -1072,6 +1063,9 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
 
        spin_lock(&gl->gl_spin);
        add_to_queue(gh);
+       if ((LM_FLAG_NOEXP & gh->gh_flags) &&
+           test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
+               set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
        run_queue(gl, 1);
        spin_unlock(&gl->gl_spin);
 
@@ -1328,6 +1322,36 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
                gfs2_glock_put(gl);
 }
 
+/**
+ * gfs2_should_freeze - Figure out if glock should be frozen
+ * @gl: The glock in question
+ *
+ * Glocks are not frozen if (a) the result of the dlm operation is
+ * an error, (b) the locking operation was an unlock operation or
+ * (c) if there is a "noexp" flagged request anywhere in the queue
+ *
+ * Returns: 1 if freezing should occur, 0 otherwise
+ */
+
+static int gfs2_should_freeze(const struct gfs2_glock *gl)
+{
+       const struct gfs2_holder *gh;
+
+       if (gl->gl_reply & ~LM_OUT_ST_MASK)
+               return 0;
+       if (gl->gl_target == LM_ST_UNLOCKED)
+               return 0;
+
+       list_for_each_entry(gh, &gl->gl_holders, gh_list) {
+               if (test_bit(HIF_HOLDER, &gh->gh_iflags))
+                       continue;
+               if (LM_FLAG_NOEXP & gh->gh_flags)
+                       return 0;
+       }
+
+       return 1;
+}
+
 /**
  * gfs2_glock_complete - Callback used by locking
  * @gl: Pointer to the glock
@@ -1338,18 +1362,17 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
 void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
 {
        struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
+
        gl->gl_reply = ret;
+
        if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) {
-               struct gfs2_holder *gh;
                spin_lock(&gl->gl_spin);
-               gh = find_first_waiter(gl);
-               if ((!(gh && (gh->gh_flags & LM_FLAG_NOEXP)) &&
-                    (gl->gl_target != LM_ST_UNLOCKED)) ||
-                   ((ret & ~LM_OUT_ST_MASK) != 0))
+               if (gfs2_should_freeze(gl)) {
                        set_bit(GLF_FROZEN, &gl->gl_flags);
-               spin_unlock(&gl->gl_spin);
-               if (test_bit(GLF_FROZEN, &gl->gl_flags))
+                       spin_unlock(&gl->gl_spin);
                        return;
+               }
+               spin_unlock(&gl->gl_spin);
        }
        set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
        gfs2_glock_hold(gl);
index b5d7363b22da08cdbcaab0c3f5188022c5f7bffe..8fcbce48a128af6414b98afe7f3d48f83dd84ef8 100644 (file)
@@ -460,6 +460,7 @@ enum {
        SDF_NOBARRIERS          = 3,
        SDF_NORECOVERY          = 4,
        SDF_DEMOTE              = 5,
+       SDF_NOJOURNALID         = 6,
 };
 
 #define GFS2_FSNAME_LEN                256
index 3593b3a7290e874b1d3d6a2238a2a83567685b04..45a4a36195d87d0819958399c56601d6702d58c1 100644 (file)
@@ -76,7 +76,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        sb->s_fs_info = sdp;
        sdp->sd_vfs = sb;
-
+       set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
        gfs2_tune_init(&sdp->sd_tune);
 
        init_waitqueue_head(&sdp->sd_glock_wait);
@@ -1050,7 +1050,8 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
                        ret = match_int(&tmp[0], &option);
                        if (ret || option < 0) 
                                goto hostdata_error;
-                       ls->ls_jid = option;
+                       if (test_and_clear_bit(SDF_NOJOURNALID, &sdp->sd_flags))
+                               ls->ls_jid = option;
                        break;
                case Opt_id:
                        /* Obsolete, but left for backward compat purposes */
@@ -1102,6 +1103,24 @@ void gfs2_lm_unmount(struct gfs2_sbd *sdp)
                lm->lm_unmount(sdp);
 }
 
+static int gfs2_journalid_wait(void *word)
+{
+       if (signal_pending(current))
+               return -EINTR;
+       schedule();
+       return 0;
+}
+
+static int wait_on_journal(struct gfs2_sbd *sdp)
+{
+       if (sdp->sd_args.ar_spectator)
+               return 0;
+       if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
+               return 0;
+
+       return wait_on_bit(&sdp->sd_flags, SDF_NOJOURNALID, gfs2_journalid_wait, TASK_INTERRUPTIBLE);
+}
+
 void gfs2_online_uevent(struct gfs2_sbd *sdp)
 {
        struct super_block *sb = sdp->sd_vfs;
@@ -1194,6 +1213,10 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
        if (error)
                goto fail_locking;
 
+       error = wait_on_journal(sdp);
+       if (error)
+               goto fail_sb;
+
        error = init_inodes(sdp, DO);
        if (error)
                goto fail_sb;
index 8f02d3db8f428fa345062fa50581f1a35c420a0e..8bb643cb2658615cf7c00e7083850c619953875a 100644 (file)
@@ -787,15 +787,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
                goto out;
 
        for (x = 0; x < num_qd; x++) {
-               int alloc_required;
-
                offset = qd2offset(qda[x]);
-               error = gfs2_write_alloc_required(ip, offset,
-                                                 sizeof(struct gfs2_quota),
-                                                 &alloc_required);
-               if (error)
-                       goto out_gunlock;
-               if (alloc_required)
+               if (gfs2_write_alloc_required(ip, offset,
+                                             sizeof(struct gfs2_quota)))
                        nalloc++;
        }
 
@@ -1584,10 +1578,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
                goto out_i;
 
        offset = qd2offset(qd);
-       error = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota),
-                                         &alloc_required);
-       if (error)
-               goto out_i;
+       alloc_required = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota));
        if (alloc_required) {
                al = gfs2_alloc_get(ip);
                if (al == NULL)
index 4d1aad38f1b136535ad6b568f3494d8ef3dec4ed..4140811a921cb7dc622a05bfa23b10e245f81daa 100644 (file)
@@ -342,8 +342,6 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
 {
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
        struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
-       int ar;
-       int error;
 
        if (ip->i_disksize < (8 << 20) || ip->i_disksize > (1 << 30) ||
            (ip->i_disksize & (sdp->sd_sb.sb_bsize - 1))) {
@@ -352,13 +350,12 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
        }
        jd->jd_blocks = ip->i_disksize >> sdp->sd_sb.sb_bsize_shift;
 
-       error = gfs2_write_alloc_required(ip, 0, ip->i_disksize, &ar);
-       if (!error && ar) {
+       if (gfs2_write_alloc_required(ip, 0, ip->i_disksize)) {
                gfs2_consist_inode(ip);
-               error = -EIO;
+               return -EIO;
        }
 
-       return error;
+       return 0;
 }
 
 /**
index 37f5393e68e6e34c96820ebb682fc2b9942e9004..d019d0d55e00eb6a79f5cc24abfaabb2ebcd71d6 100644 (file)
@@ -325,6 +325,30 @@ static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
        return sprintf(buf, "%d\n", ls->ls_first);
 }
 
+static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       unsigned first;
+       int rv;
+
+       rv = sscanf(buf, "%u", &first);
+       if (rv != 1 || first > 1)
+               return -EINVAL;
+       spin_lock(&sdp->sd_jindex_spin);
+       rv = -EBUSY;
+       if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0)
+               goto out;
+       rv = -EINVAL;
+       if (sdp->sd_args.ar_spectator)
+               goto out;
+       if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
+               goto out;
+        sdp->sd_lockstruct.ls_first = first;
+        rv = 0;
+out:
+        spin_unlock(&sdp->sd_jindex_spin);
+        return rv ? rv : len;
+}
+
 static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
@@ -377,14 +401,41 @@ static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf)
        return sprintf(buf, "%u\n", sdp->sd_lockstruct.ls_jid);
 }
 
+static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+        unsigned jid;
+       int rv;
+
+       rv = sscanf(buf, "%u", &jid);
+       if (rv != 1)
+               return -EINVAL;
+
+       spin_lock(&sdp->sd_jindex_spin);
+       rv = -EINVAL;
+       if (sdp->sd_args.ar_spectator)
+               goto out;
+       if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
+               goto out;
+       rv = -EBUSY;
+       if (test_and_clear_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0)
+               goto out;
+       sdp->sd_lockstruct.ls_jid = jid;
+       smp_mb__after_clear_bit();
+       wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
+       rv = 0;
+out:
+       spin_unlock(&sdp->sd_jindex_spin);
+       return rv ? rv : len;
+}
+
 #define GDLM_ATTR(_name,_mode,_show,_store) \
 static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
 
 GDLM_ATTR(proto_name,          0444, proto_name_show,          NULL);
 GDLM_ATTR(block,               0644, block_show,               block_store);
 GDLM_ATTR(withdraw,            0644, withdraw_show,            withdraw_store);
-GDLM_ATTR(jid,                 0444, jid_show,                 NULL);
-GDLM_ATTR(first,               0444, lkfirst_show,             NULL);
+GDLM_ATTR(jid,                 0644, jid_show,                 jid_store);
+GDLM_ATTR(first,               0644, lkfirst_show,             lkfirst_store);
 GDLM_ATTR(first_done,          0444, first_done_show,          NULL);
 GDLM_ATTR(recover,             0600, NULL,                     recover_store);
 GDLM_ATTR(recover_done,                0444, recover_done_show,        NULL);
@@ -564,7 +615,7 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
 
        add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);
        add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);
-       if (!sdp->sd_args.ar_spectator)
+       if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags))
                add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid);
        if (gfs2_uuid_valid(uuid))
                add_uevent_var(env, "UUID=%pUB", uuid);
index 868d0cb9d473a92ccdcbe640ac44f4daf24cce62..42d2d28fb827c41f5aad101e0faa340ac2dfa332 100644 (file)
@@ -282,8 +282,7 @@ int inode_permission(struct inode *inode, int mask)
        if (retval)
                return retval;
 
-       return security_inode_permission(inode,
-                       mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
+       return security_inode_permission(inode, mask);
 }
 
 /**
@@ -1484,8 +1483,7 @@ static int handle_truncate(struct path *path)
         */
        error = locks_verify_locked(inode);
        if (!error)
-               error = security_path_truncate(path, 0,
-                                      ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+               error = security_path_truncate(path);
        if (!error) {
                error = do_truncate(path->dentry, 0,
                                    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
index e60416d3f8188b548ec1d55e3438ea7e6f2c926f..832e9e2393248968b793df0302433c4e1f8b052f 100644 (file)
@@ -1953,7 +1953,7 @@ int nfs_permission(struct inode *inode, int mask)
        if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
                goto out;
        /* Is this sys_access() ? */
-       if (mask & MAY_ACCESS)
+       if (mask & (MAY_ACCESS | MAY_CHDIR))
                goto force_lookup;
 
        switch (inode->i_mode & S_IFMT) {
index 36a5e74f51b48ce00fdcb824874d7bcecdb7b8f0..f036153d9f50eaaa93bd8d8d6bc4da231a9f26d3 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pagemap.h>
 #include <linux/aio.h>
 #include <linux/gfp.h>
+#include <linux/swap.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -493,11 +494,19 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
  */
 static int nfs_release_page(struct page *page, gfp_t gfp)
 {
+       struct address_space *mapping = page->mapping;
+
        dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
 
        /* Only do I/O if gfp is a superset of GFP_KERNEL */
-       if ((gfp & GFP_KERNEL) == GFP_KERNEL)
-               nfs_wb_page(page->mapping->host, page);
+       if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) {
+               int how = FLUSH_SYNC;
+
+               /* Don't let kswapd deadlock waiting for OOM RPC calls */
+               if (current_is_kswapd())
+                       how = 0;
+               nfs_commit_inode(mapping->host, how);
+       }
        /* If PagePrivate() is set, then the page is not freeable */
        if (PagePrivate(page))
                return 0;
index 6bd19d843af7d21d0a6011589c46fb2d1586a955..df101d9f546ae294a4e370b77fa63c06bf5ab277 100644 (file)
@@ -105,7 +105,7 @@ static char nfs_root_name[256] __initdata = "";
 static __be32 servaddr __initdata = 0;
 
 /* Name of directory to mount */
-static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, };
+static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, };
 
 /* NFS-related data */
 static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
index 91679e2631ee0ebaff79cd96fd6e3019ca5a49d8..9f81bdd91c559c9f082e8fb3067cfe444da8b6b6 100644 (file)
@@ -222,7 +222,7 @@ static void nfs_end_page_writeback(struct page *page)
                clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
 }
 
-static struct nfs_page *nfs_find_and_lock_request(struct page *page)
+static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock)
 {
        struct inode *inode = page->mapping->host;
        struct nfs_page *req;
@@ -241,7 +241,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page)
                 *       request as dirty (in which case we don't care).
                 */
                spin_unlock(&inode->i_lock);
-               ret = nfs_wait_on_request(req);
+               if (!nonblock)
+                       ret = nfs_wait_on_request(req);
+               else
+                       ret = -EAGAIN;
                nfs_release_request(req);
                if (ret != 0)
                        return ERR_PTR(ret);
@@ -256,12 +259,12 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page)
  * May return an error if the user signalled nfs_wait_on_request().
  */
 static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
-                               struct page *page)
+                               struct page *page, bool nonblock)
 {
        struct nfs_page *req;
        int ret = 0;
 
-       req = nfs_find_and_lock_request(page);
+       req = nfs_find_and_lock_request(page, nonblock);
        if (!req)
                goto out;
        ret = PTR_ERR(req);
@@ -283,12 +286,20 @@ out:
 static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
 {
        struct inode *inode = page->mapping->host;
+       int ret;
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
        nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
        nfs_pageio_cond_complete(pgio, page->index);
-       return nfs_page_async_flush(pgio, page);
+       ret = nfs_page_async_flush(pgio, page,
+                       wbc->sync_mode == WB_SYNC_NONE ||
+                       wbc->nonblocking != 0);
+       if (ret == -EAGAIN) {
+               redirty_page_for_writepage(wbc, page);
+               ret = 0;
+       }
+       return ret;
 }
 
 /*
@@ -1379,7 +1390,7 @@ static const struct rpc_call_ops nfs_commit_ops = {
        .rpc_release = nfs_commit_release,
 };
 
-static int nfs_commit_inode(struct inode *inode, int how)
+int nfs_commit_inode(struct inode *inode, int how)
 {
        LIST_HEAD(head);
        int may_wait = how & FLUSH_SYNC;
@@ -1443,11 +1454,6 @@ out_mark_dirty:
        return ret;
 }
 #else
-static int nfs_commit_inode(struct inode *inode, int how)
-{
-       return 0;
-}
-
 static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc)
 {
        return 0;
@@ -1546,7 +1552,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
 
        nfs_fscache_release_page(page, GFP_KERNEL);
 
-       req = nfs_find_and_lock_request(page);
+       req = nfs_find_and_lock_request(page, false);
        ret = PTR_ERR(req);
        if (IS_ERR(req))
                goto out;
index 356e976772bf1adb112aaf3c8b28ddb71b639afb..96337a4fbbdfc3840cffc3a458ee6f37ed0655ce 100644 (file)
@@ -578,7 +578,9 @@ bail:
 static void ocfs2_dio_end_io(struct kiocb *iocb,
                             loff_t offset,
                             ssize_t bytes,
-                            void *private)
+                            void *private,
+                            int ret,
+                            bool is_async)
 {
        struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
        int level;
@@ -592,6 +594,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
        if (!level)
                up_read(&inode->i_alloc_sem);
        ocfs2_rw_unlock(inode, level);
+
+       if (is_async)
+               aio_complete(iocb, ret, 0);
 }
 
 /*
index 5463266db9e6312d906082073733c2a04440b40b..0d1fa3dc0efb53f0f42051d4dde9ac4a4503c876 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -110,7 +110,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
 
        error = locks_verify_truncate(inode, NULL, length);
        if (!error)
-               error = security_path_truncate(&path, length, 0);
+               error = security_path_truncate(&path);
        if (!error)
                error = do_truncate(path.dentry, length, 0, NULL);
 
@@ -165,8 +165,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 
        error = locks_verify_truncate(inode, file, length);
        if (!error)
-               error = security_path_truncate(&file->f_path, length,
-                                              ATTR_MTIME|ATTR_CTIME);
+               error = security_path_truncate(&file->f_path);
        if (!error)
                error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
@@ -367,7 +366,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
        if (error)
                goto out;
 
-       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
        if (error)
                goto dput_and_out;
 
@@ -396,7 +395,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
        if (!S_ISDIR(inode->i_mode))
                goto out_putf;
 
-       error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
+       error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
        if (!error)
                set_fs_pwd(current->fs, &file->f_path);
 out_putf:
@@ -414,7 +413,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
        if (error)
                goto out;
 
-       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
        if (error)
                goto dput_and_out;
 
index 9b58d38bc911e27faccc7ed9ffb2c53f0885df4a..fff6572676aed7bd337b737da35221af8fa070bb 100644 (file)
@@ -176,7 +176,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
                if (tracer)
                        tpid = task_pid_nr_ns(tracer, ns);
        }
-       cred = get_cred((struct cred *) __task_cred(p));
+       cred = get_task_cred(p);
        seq_printf(m,
                "State:\t%s\n"
                "Tgid:\t%d\n"
index ad7f67b827ea3b568d571685c42dfc50fc721920..0084a33c4c69bba01e8a264bf7a6576ddede3744 100644 (file)
@@ -1457,13 +1457,13 @@ struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
                shft -= UBIFS_LPT_FANOUT_SHIFT;
                nnode = ubifs_get_nnode(c, nnode, iip);
                if (IS_ERR(nnode))
-                       return ERR_PTR(PTR_ERR(nnode));
+                       return ERR_CAST(nnode);
        }
        iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
        shft -= UBIFS_LPT_FANOUT_SHIFT;
        pnode = ubifs_get_pnode(c, nnode, iip);
        if (IS_ERR(pnode))
-               return ERR_PTR(PTR_ERR(pnode));
+               return ERR_CAST(pnode);
        iip = (i & (UBIFS_LPT_FANOUT - 1));
        dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
               pnode->lprops[iip].free, pnode->lprops[iip].dirty,
@@ -1586,7 +1586,7 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
        nnode = c->nroot;
        nnode = dirty_cow_nnode(c, nnode);
        if (IS_ERR(nnode))
-               return ERR_PTR(PTR_ERR(nnode));
+               return ERR_CAST(nnode);
        i = lnum - c->main_first;
        shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
        for (h = 1; h < c->lpt_hght; h++) {
@@ -1594,19 +1594,19 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
                shft -= UBIFS_LPT_FANOUT_SHIFT;
                nnode = ubifs_get_nnode(c, nnode, iip);
                if (IS_ERR(nnode))
-                       return ERR_PTR(PTR_ERR(nnode));
+                       return ERR_CAST(nnode);
                nnode = dirty_cow_nnode(c, nnode);
                if (IS_ERR(nnode))
-                       return ERR_PTR(PTR_ERR(nnode));
+                       return ERR_CAST(nnode);
        }
        iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
        shft -= UBIFS_LPT_FANOUT_SHIFT;
        pnode = ubifs_get_pnode(c, nnode, iip);
        if (IS_ERR(pnode))
-               return ERR_PTR(PTR_ERR(pnode));
+               return ERR_CAST(pnode);
        pnode = dirty_cow_pnode(c, pnode);
        if (IS_ERR(pnode))
-               return ERR_PTR(PTR_ERR(pnode));
+               return ERR_CAST(pnode);
        iip = (i & (UBIFS_LPT_FANOUT - 1));
        dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
               pnode->lprops[iip].free, pnode->lprops[iip].dirty,
index 13cb7a4237bf474fa19a9161edd838c214c07c28..d12535b7fc789dda7c473593aacfc6816afc90be 100644 (file)
@@ -646,7 +646,7 @@ static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
                shft -= UBIFS_LPT_FANOUT_SHIFT;
                nnode = ubifs_get_nnode(c, nnode, iip);
                if (IS_ERR(nnode))
-                       return ERR_PTR(PTR_ERR(nnode));
+                       return ERR_CAST(nnode);
        }
        iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
        return ubifs_get_pnode(c, nnode, iip);
index 109c6ea03bb5d0cb86982a42d6ef9030e28b3e55..daae9e1f5382142482490798b0c0ba1aed581221 100644 (file)
@@ -24,7 +24,7 @@
  * This file implements functions needed to recover from unclean un-mounts.
  * When UBIFS is mounted, it checks a flag on the master node to determine if
  * an un-mount was completed successfully. If not, the process of mounting
- * incorparates additional checking and fixing of on-flash data structures.
+ * incorporates additional checking and fixing of on-flash data structures.
  * UBIFS always cleans away all remnants of an unclean un-mount, so that
  * errors do not accumulate. However UBIFS defers recovery if it is mounted
  * read-only, and the flash is not modified in that case.
@@ -1063,8 +1063,21 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
        }
        err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
        if (err) {
-               if (err == -ENOSPC)
-                       dbg_err("could not find a dirty LEB");
+               /*
+                * There are no dirty or empty LEBs subject to here being
+                * enough for the index. Try to use
+                * 'ubifs_find_free_leb_for_idx()', which will return any empty
+                * LEBs (ignoring index requirements). If the index then
+                * doesn't have enough LEBs the recovery commit will fail -
+                * which is the  same result anyway i.e. recovery fails. So
+                * there is no problem ignoring index  requirements and just
+                * grabbing a free LEB since we have already established there
+                * is not a dirty LEB we could have used instead.
+                */
+               if (err == -ENOSPC) {
+                       dbg_rcvry("could not find a dirty LEB");
+                       goto find_free;
+               }
                return err;
        }
        ubifs_assert(!(lp.flags & LPROPS_INDEX));
@@ -1139,8 +1152,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 find_free:
        /*
         * There is no GC head LEB or the free space in the GC head LEB is too
-        * small. Allocate gc_lnum by calling 'ubifs_find_free_leb_for_idx()' so
-        * GC is not run.
+        * small, or there are not dirty LEBs. Allocate gc_lnum by calling
+        * 'ubifs_find_free_leb_for_idx()' so GC is not run.
         */
        lnum = ubifs_find_free_leb_for_idx(c);
        if (lnum < 0) {
index 4d2f2157dd3fa9a70a680baea10a68fba7a56061..5fc5a0988970d15507ef048a6199c5e0f7219d65 100644 (file)
@@ -1307,6 +1307,8 @@ static int mount_ubifs(struct ubifs_info *c)
                        if (err)
                                goto out_orphans;
                        err = ubifs_rcvry_gc_commit(c);
+                       if (err)
+                               goto out_orphans;
                } else {
                        err = take_gc_lnum(c);
                        if (err)
@@ -1318,7 +1320,7 @@ static int mount_ubifs(struct ubifs_info *c)
                         */
                        err = ubifs_leb_unmap(c, c->gc_lnum);
                        if (err)
-                               return err;
+                               goto out_orphans;
                }
 
                err = dbg_check_lprops(c);
index c8fb13f83b3f1f95dc642df019a0d14072ed6d15..0dce969d6cad61840430a40f3972de64a48bfdb0 100644 (file)
@@ -87,11 +87,9 @@ xfs-y                                += xfs_alloc.o \
                                   xfs_trans_buf.o \
                                   xfs_trans_extfree.o \
                                   xfs_trans_inode.o \
-                                  xfs_trans_item.o \
                                   xfs_utils.o \
                                   xfs_vnodeops.o \
-                                  xfs_rw.o \
-                                  xfs_dmops.o
+                                  xfs_rw.o
 
 xfs-$(CONFIG_XFS_TRACE)                += xfs_btree_trace.o
 
index 9f769b5b38fc4c4b41e2b7f356889fd1d5f9a1f6..b2771862fd3df79fbb721b3c5c93865680a8e145 100644 (file)
@@ -225,7 +225,7 @@ xfs_check_acl(struct inode *inode, int mask)
        struct posix_acl *acl;
        int error = -EAGAIN;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_check_acl(ip);
 
        /*
         * If there is no attribute fork no ACL exists on this inode and
index 34640d6dbdcb8e6d5879c50a3acafed0cc819708..d24e78f32f3e3f5f41331c80f1f46e86fb700a9a 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_trans.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_alloc.h"
-#include "xfs_btree.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
 #include "xfs_iomap.h"
@@ -92,18 +85,15 @@ void
 xfs_count_page_state(
        struct page             *page,
        int                     *delalloc,
-       int                     *unmapped,
        int                     *unwritten)
 {
        struct buffer_head      *bh, *head;
 
-       *delalloc = *unmapped = *unwritten = 0;
+       *delalloc = *unwritten = 0;
 
        bh = head = page_buffers(page);
        do {
-               if (buffer_uptodate(bh) && !buffer_mapped(bh))
-                       (*unmapped) = 1;
-               else if (buffer_unwritten(bh))
+               if (buffer_unwritten(bh))
                        (*unwritten) = 1;
                else if (buffer_delay(bh))
                        (*delalloc) = 1;
@@ -212,23 +202,17 @@ xfs_setfilesize(
 }
 
 /*
- * Schedule IO completion handling on a xfsdatad if this was
- * the final hold on this ioend. If we are asked to wait,
- * flush the workqueue.
+ * Schedule IO completion handling on the final put of an ioend.
  */
 STATIC void
 xfs_finish_ioend(
-       xfs_ioend_t     *ioend,
-       int             wait)
+       struct xfs_ioend        *ioend)
 {
        if (atomic_dec_and_test(&ioend->io_remaining)) {
-               struct workqueue_struct *wq;
-
-               wq = (ioend->io_type == IO_UNWRITTEN) ?
-                       xfsconvertd_workqueue : xfsdatad_workqueue;
-               queue_work(wq, &ioend->io_work);
-               if (wait)
-                       flush_workqueue(wq);
+               if (ioend->io_type == IO_UNWRITTEN)
+                       queue_work(xfsconvertd_workqueue, &ioend->io_work);
+               else
+                       queue_work(xfsdatad_workqueue, &ioend->io_work);
        }
 }
 
@@ -272,11 +256,25 @@ xfs_end_io(
         */
        if (error == EAGAIN) {
                atomic_inc(&ioend->io_remaining);
-               xfs_finish_ioend(ioend, 0);
+               xfs_finish_ioend(ioend);
                /* ensure we don't spin on blocked ioends */
                delay(1);
-       } else
+       } else {
+               if (ioend->io_iocb)
+                       aio_complete(ioend->io_iocb, ioend->io_result, 0);
                xfs_destroy_ioend(ioend);
+       }
+}
+
+/*
+ * Call IO completion handling in caller context on the final put of an ioend.
+ */
+STATIC void
+xfs_finish_ioend_sync(
+       struct xfs_ioend        *ioend)
+{
+       if (atomic_dec_and_test(&ioend->io_remaining))
+               xfs_end_io(&ioend->io_work);
 }
 
 /*
@@ -309,6 +307,8 @@ xfs_alloc_ioend(
        atomic_inc(&XFS_I(ioend->io_inode)->i_iocount);
        ioend->io_offset = 0;
        ioend->io_size = 0;
+       ioend->io_iocb = NULL;
+       ioend->io_result = 0;
 
        INIT_WORK(&ioend->io_work, xfs_end_io);
        return ioend;
@@ -358,7 +358,7 @@ xfs_end_bio(
        bio->bi_end_io = NULL;
        bio_put(bio);
 
-       xfs_finish_ioend(ioend, 0);
+       xfs_finish_ioend(ioend);
 }
 
 STATIC void
@@ -500,7 +500,7 @@ xfs_submit_ioend(
                }
                if (bio)
                        xfs_submit_ioend_bio(wbc, ioend, bio);
-               xfs_finish_ioend(ioend, 0);
+               xfs_finish_ioend(ioend);
        } while ((ioend = next) != NULL);
 }
 
@@ -614,31 +614,30 @@ xfs_map_at_offset(
 STATIC unsigned int
 xfs_probe_page(
        struct page             *page,
-       unsigned int            pg_offset,
-       int                     mapped)
+       unsigned int            pg_offset)
 {
+       struct buffer_head      *bh, *head;
        int                     ret = 0;
 
        if (PageWriteback(page))
                return 0;
+       if (!PageDirty(page))
+               return 0;
+       if (!page->mapping)
+               return 0;
+       if (!page_has_buffers(page))
+               return 0;
 
-       if (page->mapping && PageDirty(page)) {
-               if (page_has_buffers(page)) {
-                       struct buffer_head      *bh, *head;
-
-                       bh = head = page_buffers(page);
-                       do {
-                               if (!buffer_uptodate(bh))
-                                       break;
-                               if (mapped != buffer_mapped(bh))
-                                       break;
-                               ret += bh->b_size;
-                               if (ret >= pg_offset)
-                                       break;
-                       } while ((bh = bh->b_this_page) != head);
-               } else
-                       ret = mapped ? 0 : PAGE_CACHE_SIZE;
-       }
+       bh = head = page_buffers(page);
+       do {
+               if (!buffer_uptodate(bh))
+                       break;
+               if (!buffer_mapped(bh))
+                       break;
+               ret += bh->b_size;
+               if (ret >= pg_offset)
+                       break;
+       } while ((bh = bh->b_this_page) != head);
 
        return ret;
 }
@@ -648,8 +647,7 @@ xfs_probe_cluster(
        struct inode            *inode,
        struct page             *startpage,
        struct buffer_head      *bh,
-       struct buffer_head      *head,
-       int                     mapped)
+       struct buffer_head      *head)
 {
        struct pagevec          pvec;
        pgoff_t                 tindex, tlast, tloff;
@@ -658,7 +656,7 @@ xfs_probe_cluster(
 
        /* First sum forwards in this page */
        do {
-               if (!buffer_uptodate(bh) || (mapped != buffer_mapped(bh)))
+               if (!buffer_uptodate(bh) || !buffer_mapped(bh))
                        return total;
                total += bh->b_size;
        } while ((bh = bh->b_this_page) != head);
@@ -692,7 +690,7 @@ xfs_probe_cluster(
                                pg_offset = PAGE_CACHE_SIZE;
 
                        if (page->index == tindex && trylock_page(page)) {
-                               pg_len = xfs_probe_page(page, pg_offset, mapped);
+                               pg_len = xfs_probe_page(page, pg_offset);
                                unlock_page(page);
                        }
 
@@ -761,7 +759,6 @@ xfs_convert_page(
        struct xfs_bmbt_irec    *imap,
        xfs_ioend_t             **ioendp,
        struct writeback_control *wbc,
-       int                     startio,
        int                     all_bh)
 {
        struct buffer_head      *bh, *head;
@@ -832,19 +829,14 @@ xfs_convert_page(
                        ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
 
                        xfs_map_at_offset(inode, bh, imap, offset);
-                       if (startio) {
-                               xfs_add_to_ioend(inode, bh, offset,
-                                               type, ioendp, done);
-                       } else {
-                               set_buffer_dirty(bh);
-                               unlock_buffer(bh);
-                               mark_buffer_dirty(bh);
-                       }
+                       xfs_add_to_ioend(inode, bh, offset, type,
+                                        ioendp, done);
+
                        page_dirty--;
                        count++;
                } else {
                        type = IO_NEW;
-                       if (buffer_mapped(bh) && all_bh && startio) {
+                       if (buffer_mapped(bh) && all_bh) {
                                lock_buffer(bh);
                                xfs_add_to_ioend(inode, bh, offset,
                                                type, ioendp, done);
@@ -859,14 +851,12 @@ xfs_convert_page(
        if (uptodate && bh == head)
                SetPageUptodate(page);
 
-       if (startio) {
-               if (count) {
-                       wbc->nr_to_write--;
-                       if (wbc->nr_to_write <= 0)
-                               done = 1;
-               }
-               xfs_start_page_writeback(page, !page_dirty, count);
+       if (count) {
+               wbc->nr_to_write--;
+               if (wbc->nr_to_write <= 0)
+                       done = 1;
        }
+       xfs_start_page_writeback(page, !page_dirty, count);
 
        return done;
  fail_unlock_page:
@@ -886,7 +876,6 @@ xfs_cluster_write(
        struct xfs_bmbt_irec    *imap,
        xfs_ioend_t             **ioendp,
        struct writeback_control *wbc,
-       int                     startio,
        int                     all_bh,
        pgoff_t                 tlast)
 {
@@ -902,7 +891,7 @@ xfs_cluster_write(
 
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        done = xfs_convert_page(inode, pvec.pages[i], tindex++,
-                                       imap, ioendp, wbc, startio, all_bh);
+                                       imap, ioendp, wbc, all_bh);
                        if (done)
                                break;
                }
@@ -981,7 +970,7 @@ xfs_aops_discard_page(
                 */
                error = xfs_bmapi(NULL, ip, offset_fsb, 1,
                                XFS_BMAPI_ENTIRE,  NULL, 0, &imap,
-                               &nimaps, NULL, NULL);
+                               &nimaps, NULL);
 
                if (error) {
                        /* something screwed, just bail */
@@ -1009,7 +998,7 @@ xfs_aops_discard_page(
                 */
                xfs_bmap_init(&flist, &firstblock);
                error = xfs_bunmapi(NULL, ip, offset_fsb, 1, 0, 1, &firstblock,
-                                       &flist, NULL, &done);
+                                       &flist, &done);
 
                ASSERT(!flist.xbf_count && !flist.xbf_first);
                if (error) {
@@ -1032,50 +1021,66 @@ out_invalidate:
 }
 
 /*
- * Calling this without startio set means we are being asked to make a dirty
- * page ready for freeing it's buffers.  When called with startio set then
- * we are coming from writepage.
+ * Write out a dirty page.
+ *
+ * For delalloc space on the page we need to allocate space and flush it.
+ * For unwritten space on the page we need to start the conversion to
+ * regular allocated space.
+ * For any other dirty buffer heads on the page we should flush them.
  *
- * When called with startio set it is important that we write the WHOLE
- * page if possible.
- * The bh->b_state's cannot know if any of the blocks or which block for
- * that matter are dirty due to mmap writes, and therefore bh uptodate is
- * only valid if the page itself isn't completely uptodate.  Some layers
- * may clear the page dirty flag prior to calling write page, under the
- * assumption the entire page will be written out; by not writing out the
- * whole page the page can be reused before all valid dirty data is
- * written out.  Note: in the case of a page that has been dirty'd by
- * mapwrite and but partially setup by block_prepare_write the
- * bh->b_states's will not agree and only ones setup by BPW/BCW will have
- * valid state, thus the whole page must be written out thing.
+ * If we detect that a transaction would be required to flush the page, we
+ * have to check the process flags first, if we are already in a transaction
+ * or disk I/O during allocations is off, we need to fail the writepage and
+ * redirty the page.
  */
-
 STATIC int
-xfs_page_state_convert(
-       struct inode    *inode,
-       struct page     *page,
-       struct writeback_control *wbc,
-       int             startio,
-       int             unmapped) /* also implies page uptodate */
+xfs_vm_writepage(
+       struct page             *page,
+       struct writeback_control *wbc)
 {
+       struct inode            *inode = page->mapping->host;
+       int                     delalloc, unwritten;
        struct buffer_head      *bh, *head;
        struct xfs_bmbt_irec    imap;
        xfs_ioend_t             *ioend = NULL, *iohead = NULL;
        loff_t                  offset;
-       unsigned long           p_offset = 0;
        unsigned int            type;
        __uint64_t              end_offset;
        pgoff_t                 end_index, last_index;
        ssize_t                 size, len;
        int                     flags, err, imap_valid = 0, uptodate = 1;
-       int                     page_dirty, count = 0;
-       int                     trylock = 0;
-       int                     all_bh = unmapped;
+       int                     count = 0;
+       int                     all_bh = 0;
 
-       if (startio) {
-               if (wbc->sync_mode == WB_SYNC_NONE && wbc->nonblocking)
-                       trylock |= BMAPI_TRYLOCK;
-       }
+       trace_xfs_writepage(inode, page, 0);
+
+       ASSERT(page_has_buffers(page));
+
+       /*
+        * Refuse to write the page out if we are called from reclaim context.
+        *
+        * This avoids stack overflows when called from deeply used stacks in
+        * random callers for direct reclaim or memcg reclaim.  We explicitly
+        * allow reclaim from kswapd as the stack usage there is relatively low.
+        *
+        * This should really be done by the core VM, but until that happens
+        * filesystems like XFS, btrfs and ext4 have to take care of this
+        * by themselves.
+        */
+       if ((current->flags & (PF_MEMALLOC|PF_KSWAPD)) == PF_MEMALLOC)
+               goto out_fail;
+
+       /*
+        * We need a transaction if there are delalloc or unwritten buffers
+        * on the page.
+        *
+        * If we need a transaction and the process flags say we are already
+        * in a transaction, or no IO is allowed then mark the page dirty
+        * again and leave the page as is.
+        */
+       xfs_count_page_state(page, &delalloc, &unwritten);
+       if ((current->flags & PF_FSTRANS) && (delalloc || unwritten))
+               goto out_fail;
 
        /* Is this page beyond the end of the file? */
        offset = i_size_read(inode);
@@ -1084,50 +1089,33 @@ xfs_page_state_convert(
        if (page->index >= end_index) {
                if ((page->index >= end_index + 1) ||
                    !(i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) {
-                       if (startio)
-                               unlock_page(page);
+                       unlock_page(page);
                        return 0;
                }
        }
 
-       /*
-        * page_dirty is initially a count of buffers on the page before
-        * EOF and is decremented as we move each into a cleanable state.
-        *
-        * Derivation:
-        *
-        * End offset is the highest offset that this page should represent.
-        * If we are on the last page, (end_offset & (PAGE_CACHE_SIZE - 1))
-        * will evaluate non-zero and be less than PAGE_CACHE_SIZE and
-        * hence give us the correct page_dirty count. On any other page,
-        * it will be zero and in that case we need page_dirty to be the
-        * count of buffers on the page.
-        */
        end_offset = min_t(unsigned long long,
-                       (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, offset);
+                       (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
+                       offset);
        len = 1 << inode->i_blkbits;
-       p_offset = min_t(unsigned long, end_offset & (PAGE_CACHE_SIZE - 1),
-                                       PAGE_CACHE_SIZE);
-       p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE;
-       page_dirty = p_offset / len;
 
        bh = head = page_buffers(page);
        offset = page_offset(page);
        flags = BMAPI_READ;
        type = IO_NEW;
 
-       /* TODO: cleanup count and page_dirty */
-
        do {
                if (offset >= end_offset)
                        break;
                if (!buffer_uptodate(bh))
                        uptodate = 0;
-               if (!(PageUptodate(page) || buffer_uptodate(bh)) && !startio) {
-                       /*
-                        * the iomap is actually still valid, but the ioend
-                        * isn't.  shouldn't happen too often.
-                        */
+
+               /*
+                * A hole may still be marked uptodate because discard_buffer
+                * leaves the flag set.
+                */
+               if (!buffer_mapped(bh) && buffer_uptodate(bh)) {
+                       ASSERT(!buffer_dirty(bh));
                        imap_valid = 0;
                        continue;
                }
@@ -1135,19 +1123,7 @@ xfs_page_state_convert(
                if (imap_valid)
                        imap_valid = xfs_imap_valid(inode, &imap, offset);
 
-               /*
-                * First case, map an unwritten extent and prepare for
-                * extent state conversion transaction on completion.
-                *
-                * Second case, allocate space for a delalloc buffer.
-                * We can return EAGAIN here in the release page case.
-                *
-                * Third case, an unmapped buffer was found, and we are
-                * in a path where we need to write the whole page out.
-                */
-               if (buffer_unwritten(bh) || buffer_delay(bh) ||
-                   ((buffer_uptodate(bh) || PageUptodate(page)) &&
-                    !buffer_mapped(bh) && (unmapped || startio))) {
+               if (buffer_unwritten(bh) || buffer_delay(bh)) {
                        int new_ioend = 0;
 
                        /*
@@ -1161,15 +1137,16 @@ xfs_page_state_convert(
                                flags = BMAPI_WRITE | BMAPI_IGNSTATE;
                        } else if (buffer_delay(bh)) {
                                type = IO_DELAY;
-                               flags = BMAPI_ALLOCATE | trylock;
-                       } else {
-                               type = IO_NEW;
-                               flags = BMAPI_WRITE | BMAPI_MMAP;
+                               flags = BMAPI_ALLOCATE;
+
+                               if (wbc->sync_mode == WB_SYNC_NONE &&
+                                   wbc->nonblocking)
+                                       flags |= BMAPI_TRYLOCK;
                        }
 
                        if (!imap_valid) {
                                /*
-                                * if we didn't have a valid mapping then we
+                                * If we didn't have a valid mapping then we
                                 * need to ensure that we put the new mapping
                                 * in a new ioend structure. This needs to be
                                 * done to ensure that the ioends correctly
@@ -1177,14 +1154,7 @@ xfs_page_state_convert(
                                 * for unwritten extent conversion.
                                 */
                                new_ioend = 1;
-                               if (type == IO_NEW) {
-                                       size = xfs_probe_cluster(inode,
-                                                       page, bh, head, 0);
-                               } else {
-                                       size = len;
-                               }
-
-                               err = xfs_map_blocks(inode, offset, size,
+                               err = xfs_map_blocks(inode, offset, len,
                                                &imap, flags);
                                if (err)
                                        goto error;
@@ -1193,19 +1163,11 @@ xfs_page_state_convert(
                        }
                        if (imap_valid) {
                                xfs_map_at_offset(inode, bh, &imap, offset);
-                               if (startio) {
-                                       xfs_add_to_ioend(inode, bh, offset,
-                                                       type, &ioend,
-                                                       new_ioend);
-                               } else {
-                                       set_buffer_dirty(bh);
-                                       unlock_buffer(bh);
-                                       mark_buffer_dirty(bh);
-                               }
-                               page_dirty--;
+                               xfs_add_to_ioend(inode, bh, offset, type,
+                                                &ioend, new_ioend);
                                count++;
                        }
-               } else if (buffer_uptodate(bh) && startio) {
+               } else if (buffer_uptodate(bh)) {
                        /*
                         * we got here because the buffer is already mapped.
                         * That means it must already have extents allocated
@@ -1213,8 +1175,7 @@ xfs_page_state_convert(
                         */
                        if (!imap_valid || flags != BMAPI_READ) {
                                flags = BMAPI_READ;
-                               size = xfs_probe_cluster(inode, page, bh,
-                                                               head, 1);
+                               size = xfs_probe_cluster(inode, page, bh, head);
                                err = xfs_map_blocks(inode, offset, size,
                                                &imap, flags);
                                if (err)
@@ -1233,18 +1194,16 @@ xfs_page_state_convert(
                         */
                        type = IO_NEW;
                        if (trylock_buffer(bh)) {
-                               ASSERT(buffer_mapped(bh));
                                if (imap_valid)
                                        all_bh = 1;
                                xfs_add_to_ioend(inode, bh, offset, type,
                                                &ioend, !imap_valid);
-                               page_dirty--;
                                count++;
                        } else {
                                imap_valid = 0;
                        }
-               } else if ((buffer_uptodate(bh) || PageUptodate(page)) &&
-                          (unmapped || startio)) {
+               } else if (PageUptodate(page)) {
+                       ASSERT(buffer_mapped(bh));
                        imap_valid = 0;
                }
 
@@ -1256,8 +1215,7 @@ xfs_page_state_convert(
        if (uptodate && bh == head)
                SetPageUptodate(page);
 
-       if (startio)
-               xfs_start_page_writeback(page, 1, count);
+       xfs_start_page_writeback(page, 1, count);
 
        if (ioend && imap_valid) {
                xfs_off_t               end_index;
@@ -1275,131 +1233,27 @@ xfs_page_state_convert(
                        end_index = last_index;
 
                xfs_cluster_write(inode, page->index + 1, &imap, &ioend,
-                                       wbc, startio, all_bh, end_index);
+                                       wbc, all_bh, end_index);
        }
 
        if (iohead)
                xfs_submit_ioend(wbc, iohead);
 
-       return page_dirty;
+       return 0;
 
 error:
        if (iohead)
                xfs_cancel_ioend(iohead);
 
-       /*
-        * If it's delalloc and we have nowhere to put it,
-        * throw it away, unless the lower layers told
-        * us to try again.
-        */
-       if (err != -EAGAIN) {
-               if (!unmapped)
-                       xfs_aops_discard_page(page);
-               ClearPageUptodate(page);
-       }
+       xfs_aops_discard_page(page);
+       ClearPageUptodate(page);
+       unlock_page(page);
        return err;
-}
-
-/*
- * writepage: Called from one of two places:
- *
- * 1. we are flushing a delalloc buffer head.
- *
- * 2. we are writing out a dirty page. Typically the page dirty
- *    state is cleared before we get here. In this case is it
- *    conceivable we have no buffer heads.
- *
- * For delalloc space on the page we need to allocate space and
- * flush it. For unmapped buffer heads on the page we should
- * allocate space if the page is uptodate. For any other dirty
- * buffer heads on the page we should flush them.
- *
- * If we detect that a transaction would be required to flush
- * the page, we have to check the process flags first, if we
- * are already in a transaction or disk I/O during allocations
- * is off, we need to fail the writepage and redirty the page.
- */
-
-STATIC int
-xfs_vm_writepage(
-       struct page             *page,
-       struct writeback_control *wbc)
-{
-       int                     error;
-       int                     need_trans;
-       int                     delalloc, unmapped, unwritten;
-       struct inode            *inode = page->mapping->host;
-
-       trace_xfs_writepage(inode, page, 0);
-
-       /*
-        * Refuse to write the page out if we are called from reclaim context.
-        *
-        * This is primarily to avoid stack overflows when called from deep
-        * used stacks in random callers for direct reclaim, but disabling
-        * reclaim for kswap is a nice side-effect as kswapd causes rather
-        * suboptimal I/O patters, too.
-        *
-        * This should really be done by the core VM, but until that happens
-        * filesystems like XFS, btrfs and ext4 have to take care of this
-        * by themselves.
-        */
-       if (current->flags & PF_MEMALLOC)
-               goto out_fail;
-
-       /*
-        * We need a transaction if:
-        *  1. There are delalloc buffers on the page
-        *  2. The page is uptodate and we have unmapped buffers
-        *  3. The page is uptodate and we have no buffers
-        *  4. There are unwritten buffers on the page
-        */
-
-       if (!page_has_buffers(page)) {
-               unmapped = 1;
-               need_trans = 1;
-       } else {
-               xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
-               if (!PageUptodate(page))
-                       unmapped = 0;
-               need_trans = delalloc + unmapped + unwritten;
-       }
-
-       /*
-        * If we need a transaction and the process flags say
-        * we are already in a transaction, or no IO is allowed
-        * then mark the page dirty again and leave the page
-        * as is.
-        */
-       if (current_test_flags(PF_FSTRANS) && need_trans)
-               goto out_fail;
-
-       /*
-        * Delay hooking up buffer heads until we have
-        * made our go/no-go decision.
-        */
-       if (!page_has_buffers(page))
-               create_empty_buffers(page, 1 << inode->i_blkbits, 0);
-
-       /*
-        * Convert delayed allocate, unwritten or unmapped space
-        * to real space and flush out to disk.
-        */
-       error = xfs_page_state_convert(inode, page, wbc, 1, unmapped);
-       if (error == -EAGAIN)
-               goto out_fail;
-       if (unlikely(error < 0))
-               goto out_unlock;
-
-       return 0;
 
 out_fail:
        redirty_page_for_writepage(wbc, page);
        unlock_page(page);
        return 0;
-out_unlock:
-       unlock_page(page);
-       return error;
 }
 
 STATIC int
@@ -1413,65 +1267,27 @@ xfs_vm_writepages(
 
 /*
  * Called to move a page into cleanable state - and from there
- * to be released. Possibly the page is already clean. We always
+ * to be released. The page should already be clean. We always
  * have buffer heads in this call.
  *
- * Returns 0 if the page is ok to release, 1 otherwise.
- *
- * Possible scenarios are:
- *
- * 1. We are being called to release a page which has been written
- *    to via regular I/O. buffer heads will be dirty and possibly
- *    delalloc. If no delalloc buffer heads in this case then we
- *    can just return zero.
- *
- * 2. We are called to release a page which has been written via
- *    mmap, all we need to do is ensure there is no delalloc
- *    state in the buffer heads, if not we can let the caller
- *    free them and we should come back later via writepage.
+ * Returns 1 if the page is ok to release, 0 otherwise.
  */
 STATIC int
 xfs_vm_releasepage(
        struct page             *page,
        gfp_t                   gfp_mask)
 {
-       struct inode            *inode = page->mapping->host;
-       int                     dirty, delalloc, unmapped, unwritten;
-       struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = 1,
-       };
+       int                     delalloc, unwritten;
 
-       trace_xfs_releasepage(inode, page, 0);
-
-       if (!page_has_buffers(page))
-               return 0;
+       trace_xfs_releasepage(page->mapping->host, page, 0);
 
-       xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
-       if (!delalloc && !unwritten)
-               goto free_buffers;
+       xfs_count_page_state(page, &delalloc, &unwritten);
 
-       if (!(gfp_mask & __GFP_FS))
+       if (WARN_ON(delalloc))
                return 0;
-
-       /* If we are already inside a transaction or the thread cannot
-        * do I/O, we cannot release this page.
-        */
-       if (current_test_flags(PF_FSTRANS))
+       if (WARN_ON(unwritten))
                return 0;
 
-       /*
-        * Convert delalloc space to real space, do not flush the
-        * data out to disk, that will be done by the caller.
-        * Never need to allocate space here - we will always
-        * come back to writepage in that case.
-        */
-       dirty = xfs_page_state_convert(inode, page, &wbc, 0, 0);
-       if (dirty == 0 && !unwritten)
-               goto free_buffers;
-       return 0;
-
-free_buffers:
        return try_to_free_buffers(page);
 }
 
@@ -1481,9 +1297,9 @@ __xfs_get_blocks(
        sector_t                iblock,
        struct buffer_head      *bh_result,
        int                     create,
-       int                     direct,
-       bmapi_flags_t           flags)
+       int                     direct)
 {
+       int                     flags = create ? BMAPI_WRITE : BMAPI_READ;
        struct xfs_bmbt_irec    imap;
        xfs_off_t               offset;
        ssize_t                 size;
@@ -1498,8 +1314,11 @@ __xfs_get_blocks(
        if (!create && direct && offset >= i_size_read(inode))
                return 0;
 
-       error = xfs_iomap(XFS_I(inode), offset, size,
-                            create ? flags : BMAPI_READ, &imap, &nimap, &new);
+       if (direct && create)
+               flags |= BMAPI_DIRECT;
+
+       error = xfs_iomap(XFS_I(inode), offset, size, flags, &imap, &nimap,
+                         &new);
        if (error)
                return -error;
        if (nimap == 0)
@@ -1579,8 +1398,7 @@ xfs_get_blocks(
        struct buffer_head      *bh_result,
        int                     create)
 {
-       return __xfs_get_blocks(inode, iblock,
-                               bh_result, create, 0, BMAPI_WRITE);
+       return __xfs_get_blocks(inode, iblock, bh_result, create, 0);
 }
 
 STATIC int
@@ -1590,61 +1408,59 @@ xfs_get_blocks_direct(
        struct buffer_head      *bh_result,
        int                     create)
 {
-       return __xfs_get_blocks(inode, iblock,
-                               bh_result, create, 1, BMAPI_WRITE|BMAPI_DIRECT);
+       return __xfs_get_blocks(inode, iblock, bh_result, create, 1);
 }
 
+/*
+ * Complete a direct I/O write request.
+ *
+ * If the private argument is non-NULL __xfs_get_blocks signals us that we
+ * need to issue a transaction to convert the range from unwritten to written
+ * extents.  In case this is regular synchronous I/O we just call xfs_end_io
+ * to do this and we are done.  But in case this was a successfull AIO
+ * request this handler is called from interrupt context, from which we
+ * can't start transactions.  In that case offload the I/O completion to
+ * the workqueues we also use for buffered I/O completion.
+ */
 STATIC void
-xfs_end_io_direct(
-       struct kiocb    *iocb,
-       loff_t          offset,
-       ssize_t         size,
-       void            *private)
+xfs_end_io_direct_write(
+       struct kiocb            *iocb,
+       loff_t                  offset,
+       ssize_t                 size,
+       void                    *private,
+       int                     ret,
+       bool                    is_async)
 {
-       xfs_ioend_t     *ioend = iocb->private;
+       struct xfs_ioend        *ioend = iocb->private;
 
        /*
-        * Non-NULL private data means we need to issue a transaction to
-        * convert a range from unwritten to written extents.  This needs
-        * to happen from process context but aio+dio I/O completion
-        * happens from irq context so we need to defer it to a workqueue.
-        * This is not necessary for synchronous direct I/O, but we do
-        * it anyway to keep the code uniform and simpler.
-        *
-        * Well, if only it were that simple. Because synchronous direct I/O
-        * requires extent conversion to occur *before* we return to userspace,
-        * we have to wait for extent conversion to complete. Look at the
-        * iocb that has been passed to us to determine if this is AIO or
-        * not. If it is synchronous, tell xfs_finish_ioend() to kick the
-        * workqueue and wait for it to complete.
-        *
-        * The core direct I/O code might be changed to always call the
-        * completion handler in the future, in which case all this can
-        * go away.
+        * blockdev_direct_IO can return an error even after the I/O
+        * completion handler was called.  Thus we need to protect
+        * against double-freeing.
         */
+       iocb->private = NULL;
+
        ioend->io_offset = offset;
        ioend->io_size = size;
-       if (ioend->io_type == IO_READ) {
-               xfs_finish_ioend(ioend, 0);
-       } else if (private && size > 0) {
-               xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
-       } else {
+       if (private && size > 0)
+               ioend->io_type = IO_UNWRITTEN;
+
+       if (is_async) {
                /*
-                * A direct I/O write ioend starts it's life in unwritten
-                * state in case they map an unwritten extent.  This write
-                * didn't map an unwritten extent so switch it's completion
-                * handler.
+                * If we are converting an unwritten extent we need to delay
+                * the AIO completion until after the unwrittent extent
+                * conversion has completed, otherwise do it ASAP.
                 */
-               ioend->io_type = IO_NEW;
-               xfs_finish_ioend(ioend, 0);
+               if (ioend->io_type == IO_UNWRITTEN) {
+                       ioend->io_iocb = iocb;
+                       ioend->io_result = ret;
+               } else {
+                       aio_complete(iocb, ret, 0);
+               }
+               xfs_finish_ioend(ioend);
+       } else {
+               xfs_finish_ioend_sync(ioend);
        }
-
-       /*
-        * blockdev_direct_IO can return an error even after the I/O
-        * completion handler was called.  Thus we need to protect
-        * against double-freeing.
-        */
-       iocb->private = NULL;
 }
 
 STATIC ssize_t
@@ -1655,23 +1471,26 @@ xfs_vm_direct_IO(
        loff_t                  offset,
        unsigned long           nr_segs)
 {
-       struct file     *file = iocb->ki_filp;
-       struct inode    *inode = file->f_mapping->host;
-       struct block_device *bdev;
-       ssize_t         ret;
-
-       bdev = xfs_find_bdev_for_inode(inode);
-
-       iocb->private = xfs_alloc_ioend(inode, rw == WRITE ?
-                                       IO_UNWRITTEN : IO_READ);
-
-       ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
-                                           offset, nr_segs,
-                                           xfs_get_blocks_direct,
-                                           xfs_end_io_direct);
+       struct inode            *inode = iocb->ki_filp->f_mapping->host;
+       struct block_device     *bdev = xfs_find_bdev_for_inode(inode);
+       ssize_t                 ret;
+
+       if (rw & WRITE) {
+               iocb->private = xfs_alloc_ioend(inode, IO_NEW);
+
+               ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
+                                                   offset, nr_segs,
+                                                   xfs_get_blocks_direct,
+                                                   xfs_end_io_direct_write);
+               if (ret != -EIOCBQUEUED && iocb->private)
+                       xfs_destroy_ioend(iocb->private);
+       } else {
+               ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
+                                                   offset, nr_segs,
+                                                   xfs_get_blocks_direct,
+                                                   NULL);
+       }
 
-       if (unlikely(ret != -EIOCBQUEUED && iocb->private))
-               xfs_destroy_ioend(iocb->private);
        return ret;
 }
 
@@ -1686,8 +1505,8 @@ xfs_vm_write_begin(
        void                    **fsdata)
 {
        *pagep = NULL;
-       return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                               xfs_get_blocks);
+       return block_write_begin(file, mapping, pos, len, flags | AOP_FLAG_NOFS,
+                                pagep, fsdata, xfs_get_blocks);
 }
 
 STATIC sector_t
@@ -1698,7 +1517,7 @@ xfs_vm_bmap(
        struct inode            *inode = (struct inode *)mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
 
-       xfs_itrace_entry(XFS_I(inode));
+       trace_xfs_vm_bmap(XFS_I(inode));
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
        xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF);
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
index 4cfc6ea87df8c4c34564da66ee31aba497dad902..c5057fb6237a2c71bd94b5ad4abe046bf7a37e9e 100644 (file)
@@ -37,6 +37,8 @@ typedef struct xfs_ioend {
        size_t                  io_size;        /* size of the extent */
        xfs_off_t               io_offset;      /* offset in the file */
        struct work_struct      io_work;        /* xfsdatad work queue */
+       struct kiocb            *io_iocb;
+       int                     io_result;
 } xfs_ioend_t;
 
 extern const struct address_space_operations xfs_address_space_operations;
@@ -45,6 +47,6 @@ extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
 extern void xfs_ioend_init(void);
 extern void xfs_ioend_wait(struct xfs_inode *);
 
-extern void xfs_count_page_state(struct page *, int *, int *, int *);
+extern void xfs_count_page_state(struct page *, int *, int *);
 
 #endif /* __XFS_AOPS_H__ */
index 2ee3f7a60163e899e971700aba008a243049726a..ea79072f521012549c4c2673a6210340834202a4 100644 (file)
@@ -39,7 +39,6 @@
 #include "xfs_inum.h"
 #include "xfs_log.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trace.h"
 
@@ -579,9 +578,9 @@ _xfs_buf_read(
                        XBF_READ_AHEAD | _XBF_RUN_QUEUES);
 
        status = xfs_buf_iorequest(bp);
-       if (!status && !(flags & XBF_ASYNC))
-               status = xfs_buf_iowait(bp);
-       return status;
+       if (status || XFS_BUF_ISERROR(bp) || (flags & XBF_ASYNC))
+               return status;
+       return xfs_buf_iowait(bp);
 }
 
 xfs_buf_t *
@@ -897,36 +896,6 @@ xfs_buf_unlock(
        trace_xfs_buf_unlock(bp, _RET_IP_);
 }
 
-
-/*
- *     Pinning Buffer Storage in Memory
- *     Ensure that no attempt to force a buffer to disk will succeed.
- */
-void
-xfs_buf_pin(
-       xfs_buf_t               *bp)
-{
-       trace_xfs_buf_pin(bp, _RET_IP_);
-       atomic_inc(&bp->b_pin_count);
-}
-
-void
-xfs_buf_unpin(
-       xfs_buf_t               *bp)
-{
-       trace_xfs_buf_unpin(bp, _RET_IP_);
-
-       if (atomic_dec_and_test(&bp->b_pin_count))
-               wake_up_all(&bp->b_waiters);
-}
-
-int
-xfs_buf_ispin(
-       xfs_buf_t               *bp)
-{
-       return atomic_read(&bp->b_pin_count);
-}
-
 STATIC void
 xfs_buf_wait_unpin(
        xfs_buf_t               *bp)
@@ -1018,13 +987,12 @@ xfs_bwrite(
 {
        int                     error;
 
-       bp->b_strat = xfs_bdstrat_cb;
        bp->b_mount = mp;
        bp->b_flags |= XBF_WRITE;
        bp->b_flags &= ~(XBF_ASYNC | XBF_READ);
 
        xfs_buf_delwri_dequeue(bp);
-       xfs_buf_iostrategy(bp);
+       xfs_bdstrat_cb(bp);
 
        error = xfs_buf_iowait(bp);
        if (error)
@@ -1040,7 +1008,6 @@ xfs_bdwrite(
 {
        trace_xfs_buf_bdwrite(bp, _RET_IP_);
 
-       bp->b_strat = xfs_bdstrat_cb;
        bp->b_mount = mp;
 
        bp->b_flags &= ~XBF_READ;
@@ -1075,7 +1042,6 @@ xfs_bioerror(
        XFS_BUF_UNDONE(bp);
        XFS_BUF_STALE(bp);
 
-       XFS_BUF_CLR_BDSTRAT_FUNC(bp);
        xfs_biodone(bp);
 
        return EIO;
@@ -1105,7 +1071,6 @@ xfs_bioerror_relse(
        XFS_BUF_DONE(bp);
        XFS_BUF_STALE(bp);
        XFS_BUF_CLR_IODONE_FUNC(bp);
-       XFS_BUF_CLR_BDSTRAT_FUNC(bp);
        if (!(fl & XBF_ASYNC)) {
                /*
                 * Mark b_error and B_ERROR _both_.
@@ -1311,8 +1276,19 @@ submit_io:
                if (size)
                        goto next_chunk;
        } else {
-               bio_put(bio);
+               /*
+                * if we get here, no pages were added to the bio. However,
+                * we can't just error out here - if the pages are locked then
+                * we have to unlock them otherwise we can hang on a later
+                * access to the page.
+                */
                xfs_buf_ioerror(bp, EIO);
+               if (bp->b_flags & _XBF_PAGE_LOCKED) {
+                       int i;
+                       for (i = 0; i < bp->b_page_count; i++)
+                               unlock_page(bp->b_pages[i]);
+               }
+               bio_put(bio);
        }
 }
 
@@ -1804,7 +1780,7 @@ xfs_buf_delwri_split(
                trace_xfs_buf_delwri_split(bp, _RET_IP_);
                ASSERT(bp->b_flags & XBF_DELWRI);
 
-               if (!xfs_buf_ispin(bp) && !xfs_buf_cond_lock(bp)) {
+               if (!XFS_BUF_ISPINNED(bp) && !xfs_buf_cond_lock(bp)) {
                        if (!force &&
                            time_before(jiffies, bp->b_queuetime + age)) {
                                xfs_buf_unlock(bp);
@@ -1889,7 +1865,7 @@ xfsbufd(
                        struct xfs_buf *bp;
                        bp = list_first_entry(&tmp, struct xfs_buf, b_list);
                        list_del_init(&bp->b_list);
-                       xfs_buf_iostrategy(bp);
+                       xfs_bdstrat_cb(bp);
                        count++;
                }
                if (count)
@@ -1936,7 +1912,7 @@ xfs_flush_buftarg(
                        bp->b_flags &= ~XBF_ASYNC;
                        list_add(&bp->b_list, &wait_list);
                }
-               xfs_buf_iostrategy(bp);
+               xfs_bdstrat_cb(bp);
        }
 
        if (wait) {
index 5fbecefa5dfd69a9807cad3a4f4d786e579d0062..d072e5ff923b3e71eac4000bd432cd84d72e0d9b 100644 (file)
@@ -44,57 +44,57 @@ typedef enum {
        XBRW_ZERO = 3,                  /* Zero target memory */
 } xfs_buf_rw_t;
 
-typedef enum {
-       XBF_READ = (1 << 0),    /* buffer intended for reading from device */
-       XBF_WRITE = (1 << 1),   /* buffer intended for writing to device   */
-       XBF_MAPPED = (1 << 2),  /* buffer mapped (b_addr valid)            */
-       XBF_ASYNC = (1 << 4),   /* initiator will not wait for completion  */
-       XBF_DONE = (1 << 5),    /* all pages in the buffer uptodate        */
-       XBF_DELWRI = (1 << 6),  /* buffer has dirty pages                  */
-       XBF_STALE = (1 << 7),   /* buffer has been staled, do not find it  */
-       XBF_FS_MANAGED = (1 << 8),  /* filesystem controls freeing memory  */
-       XBF_ORDERED = (1 << 11),    /* use ordered writes                  */
-       XBF_READ_AHEAD = (1 << 12), /* asynchronous read-ahead             */
-       XBF_LOG_BUFFER = (1 << 13), /* this is a buffer used for the log   */
-
-       /* flags used only as arguments to access routines */
-       XBF_LOCK = (1 << 14),       /* lock requested                      */
-       XBF_TRYLOCK = (1 << 15),    /* lock requested, but do not wait     */
-       XBF_DONT_BLOCK = (1 << 16), /* do not block in current thread      */
-
-       /* flags used only internally */
-       _XBF_PAGE_CACHE = (1 << 17),/* backed by pagecache                 */
-       _XBF_PAGES = (1 << 18),     /* backed by refcounted pages          */
-       _XBF_RUN_QUEUES = (1 << 19),/* run block device task queue         */
-       _XBF_DELWRI_Q = (1 << 21),   /* buffer on delwri queue             */
-
-       /*
-        * Special flag for supporting metadata blocks smaller than a FSB.
-        *
-        * In this case we can have multiple xfs_buf_t on a single page and
-        * need to lock out concurrent xfs_buf_t readers as they only
-        * serialise access to the buffer.
-        *
-        * If the FSB size >= PAGE_CACHE_SIZE case, we have no serialisation
-        * between reads of the page. Hence we can have one thread read the
-        * page and modify it, but then race with another thread that thinks
-        * the page is not up-to-date and hence reads it again.
-        *
-        * The result is that the first modifcation to the page is lost.
-        * This sort of AGF/AGI reading race can happen when unlinking inodes
-        * that require truncation and results in the AGI unlinked list
-        * modifications being lost.
-        */
-       _XBF_PAGE_LOCKED = (1 << 22),
-
-       /*
-        * If we try a barrier write, but it fails we have to communicate
-        * this to the upper layers.  Unfortunately b_error gets overwritten
-        * when the buffer is re-issued so we have to add another flag to
-        * keep this information.
-        */
-       _XFS_BARRIER_FAILED = (1 << 23),
-} xfs_buf_flags_t;
+#define XBF_READ       (1 << 0) /* buffer intended for reading from device */
+#define XBF_WRITE      (1 << 1) /* buffer intended for writing to device */
+#define XBF_MAPPED     (1 << 2) /* buffer mapped (b_addr valid) */
+#define XBF_ASYNC      (1 << 4) /* initiator will not wait for completion */
+#define XBF_DONE       (1 << 5) /* all pages in the buffer uptodate */
+#define XBF_DELWRI     (1 << 6) /* buffer has dirty pages */
+#define XBF_STALE      (1 << 7) /* buffer has been staled, do not find it */
+#define XBF_FS_MANAGED (1 << 8) /* filesystem controls freeing memory */
+#define XBF_ORDERED    (1 << 11)/* use ordered writes */
+#define XBF_READ_AHEAD (1 << 12)/* asynchronous read-ahead */
+#define XBF_LOG_BUFFER (1 << 13)/* this is a buffer used for the log */
+
+/* flags used only as arguments to access routines */
+#define XBF_LOCK       (1 << 14)/* lock requested */
+#define XBF_TRYLOCK    (1 << 15)/* lock requested, but do not wait */
+#define XBF_DONT_BLOCK (1 << 16)/* do not block in current thread */
+
+/* flags used only internally */
+#define _XBF_PAGE_CACHE        (1 << 17)/* backed by pagecache */
+#define _XBF_PAGES     (1 << 18)/* backed by refcounted pages */
+#define        _XBF_RUN_QUEUES (1 << 19)/* run block device task queue */
+#define _XBF_DELWRI_Q  (1 << 21)/* buffer on delwri queue */
+
+/*
+ * Special flag for supporting metadata blocks smaller than a FSB.
+ *
+ * In this case we can have multiple xfs_buf_t on a single page and
+ * need to lock out concurrent xfs_buf_t readers as they only
+ * serialise access to the buffer.
+ *
+ * If the FSB size >= PAGE_CACHE_SIZE case, we have no serialisation
+ * between reads of the page. Hence we can have one thread read the
+ * page and modify it, but then race with another thread that thinks
+ * the page is not up-to-date and hence reads it again.
+ *
+ * The result is that the first modifcation to the page is lost.
+ * This sort of AGF/AGI reading race can happen when unlinking inodes
+ * that require truncation and results in the AGI unlinked list
+ * modifications being lost.
+ */
+#define _XBF_PAGE_LOCKED       (1 << 22)
+
+/*
+ * If we try a barrier write, but it fails we have to communicate
+ * this to the upper layers.  Unfortunately b_error gets overwritten
+ * when the buffer is re-issued so we have to add another flag to
+ * keep this information.
+ */
+#define _XFS_BARRIER_FAILED    (1 << 23)
+
+typedef unsigned int xfs_buf_flags_t;
 
 #define XFS_BUF_FLAGS \
        { XBF_READ,             "READ" }, \
@@ -187,7 +187,6 @@ typedef struct xfs_buf {
        atomic_t                b_io_remaining; /* #outstanding I/O requests */
        xfs_buf_iodone_t        b_iodone;       /* I/O completion function */
        xfs_buf_relse_t         b_relse;        /* releasing function */
-       xfs_buf_bdstrat_t       b_strat;        /* pre-write function */
        struct completion       b_iowait;       /* queue for I/O waiters */
        void                    *b_fspriv;
        void                    *b_fspriv2;
@@ -245,11 +244,6 @@ extern int xfs_buf_iowait(xfs_buf_t *);
 extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
                                xfs_buf_rw_t);
 
-static inline int xfs_buf_iostrategy(xfs_buf_t *bp)
-{
-       return bp->b_strat ? bp->b_strat(bp) : xfs_buf_iorequest(bp);
-}
-
 static inline int xfs_buf_geterror(xfs_buf_t *bp)
 {
        return bp ? bp->b_error : ENOMEM;
@@ -258,11 +252,6 @@ static inline int xfs_buf_geterror(xfs_buf_t *bp)
 /* Buffer Utility Routines */
 extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
 
-/* Pinning Buffer Storage in Memory */
-extern void xfs_buf_pin(xfs_buf_t *);
-extern void xfs_buf_unpin(xfs_buf_t *);
-extern int xfs_buf_ispin(xfs_buf_t *);
-
 /* Delayed Write Buffer Routines */
 extern void xfs_buf_delwri_dequeue(xfs_buf_t *);
 extern void xfs_buf_delwri_promote(xfs_buf_t *);
@@ -326,8 +315,6 @@ extern void xfs_buf_terminate(void);
 #define XFS_BUF_IODONE_FUNC(bp)                        ((bp)->b_iodone)
 #define XFS_BUF_SET_IODONE_FUNC(bp, func)      ((bp)->b_iodone = (func))
 #define XFS_BUF_CLR_IODONE_FUNC(bp)            ((bp)->b_iodone = NULL)
-#define XFS_BUF_SET_BDSTRAT_FUNC(bp, func)     ((bp)->b_strat = (func))
-#define XFS_BUF_CLR_BDSTRAT_FUNC(bp)           ((bp)->b_strat = NULL)
 
 #define XFS_BUF_FSPRIVATE(bp, type)            ((type)(bp)->b_fspriv)
 #define XFS_BUF_SET_FSPRIVATE(bp, val)         ((bp)->b_fspriv = (void*)(val))
@@ -351,7 +338,7 @@ extern void xfs_buf_terminate(void);
 #define XFS_BUF_SET_VTYPE(bp, type)            do { } while (0)
 #define XFS_BUF_SET_REF(bp, ref)               do { } while (0)
 
-#define XFS_BUF_ISPINNED(bp)   xfs_buf_ispin(bp)
+#define XFS_BUF_ISPINNED(bp)   atomic_read(&((bp)->b_pin_count))
 
 #define XFS_BUF_VALUSEMA(bp)   xfs_buf_lock_value(bp)
 #define XFS_BUF_CPSEMA(bp)     (xfs_buf_cond_lock(bp) == 0)
@@ -370,8 +357,6 @@ static inline void xfs_buf_relse(xfs_buf_t *bp)
        xfs_buf_rele(bp);
 }
 
-#define xfs_bpin(bp)           xfs_buf_pin(bp)
-#define xfs_bunpin(bp)         xfs_buf_unpin(bp)
 #define xfs_biodone(bp)                xfs_buf_ioend(bp, 0)
 
 #define xfs_biomove(bp, off, len, data, rw) \
diff --git a/fs/xfs/linux-2.6/xfs_dmapi_priv.h b/fs/xfs/linux-2.6/xfs_dmapi_priv.h
deleted file mode 100644 (file)
index a8b0b16..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2000-2006 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_DMAPI_PRIV_H__
-#define __XFS_DMAPI_PRIV_H__
-
-/*
- *     Based on IO_ISDIRECT, decide which i_ flag is set.
- */
-#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \
-                             DM_FLAGS_IMUX : 0)
-#define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_IMUX)
-
-#endif /*__XFS_DMAPI_PRIV_H__*/
index e7839ee49e43656d0d1edfa7011ce8d9eb0e97b2..3764d74790ecc5c8dc5301e36dd1605f5af045e8 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_export.h"
 #include "xfs_vnodeops.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
+#include "xfs_trace.h"
 
 /*
  * Note that we only accept fileids which are long enough rather than allow
@@ -132,8 +132,7 @@ xfs_nfs_get_inode(
         * fine and not an indication of a corrupted filesystem as clients can
         * send invalid file handles and we have to handle it gracefully..
         */
-       error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED,
-                        XFS_ILOCK_SHARED, &ip);
+       error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
        if (error) {
                /*
                 * EINVAL means the inode cluster doesn't exist anymore.
@@ -148,11 +147,10 @@ xfs_nfs_get_inode(
        }
 
        if (ip->i_d.di_gen != generation) {
-               xfs_iput_new(ip, XFS_ILOCK_SHARED);
+               IRELE(ip);
                return ERR_PTR(-ENOENT);
        }
 
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
        return VFS_I(ip);
 }
 
index 257a56b127cf060013569a211de51efd7f2b1306..ba8ad422a16506fdea605c7a215e572b3b3a8f6a 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_trans.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
 #include "xfs_alloc.h"
-#include "xfs_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_vnodeops.h"
 #include "xfs_da_btree.h"
 #include "xfs_ioctl.h"
@@ -108,7 +100,7 @@ xfs_file_fsync(
        int                     error = 0;
        int                     log_flushed = 0;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_file_fsync(ip);
 
        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
                return -XFS_ERROR(EIO);
@@ -166,8 +158,7 @@ xfs_file_fsync(
                 * transaction.  So we play it safe and fire off the
                 * transaction anyway.
                 */
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
                xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
                xfs_trans_set_sync(tp);
                error = _xfs_trans_commit(tp, 0, &log_flushed);
@@ -275,20 +266,6 @@ xfs_file_aio_read(
                mutex_lock(&inode->i_mutex);
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-       if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) {
-               int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags);
-               int iolock = XFS_IOLOCK_SHARED;
-
-               ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, ip, iocb->ki_pos, size,
-                                       dmflags, &iolock);
-               if (ret) {
-                       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-                       if (unlikely(ioflags & IO_ISDIRECT))
-                               mutex_unlock(&inode->i_mutex);
-                       return ret;
-               }
-       }
-
        if (unlikely(ioflags & IO_ISDIRECT)) {
                if (inode->i_mapping->nrpages) {
                        ret = -xfs_flushinval_pages(ip,
@@ -321,7 +298,6 @@ xfs_file_splice_read(
        unsigned int            flags)
 {
        struct xfs_inode        *ip = XFS_I(infilp->f_mapping->host);
-       struct xfs_mount        *mp = ip->i_mount;
        int                     ioflags = 0;
        ssize_t                 ret;
 
@@ -335,18 +311,6 @@ xfs_file_splice_read(
 
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-       if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) {
-               int iolock = XFS_IOLOCK_SHARED;
-               int error;
-
-               error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, *ppos, count,
-                                       FILP_DELAY_FLAG(infilp), &iolock);
-               if (error) {
-                       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-                       return -error;
-               }
-       }
-
        trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
 
        ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
@@ -367,7 +331,6 @@ xfs_file_splice_write(
 {
        struct inode            *inode = outfilp->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
        xfs_fsize_t             isize, new_size;
        int                     ioflags = 0;
        ssize_t                 ret;
@@ -382,18 +345,6 @@ xfs_file_splice_write(
 
        xfs_ilock(ip, XFS_IOLOCK_EXCL);
 
-       if (DM_EVENT_ENABLED(ip, DM_EVENT_WRITE) && !(ioflags & IO_INVIS)) {
-               int iolock = XFS_IOLOCK_EXCL;
-               int error;
-
-               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, *ppos, count,
-                                       FILP_DELAY_FLAG(outfilp), &iolock);
-               if (error) {
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return -error;
-               }
-       }
-
        new_size = *ppos + count;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -463,7 +414,7 @@ xfs_zero_last_block(
        last_fsb = XFS_B_TO_FSBT(mp, isize);
        nimaps = 1;
        error = xfs_bmapi(NULL, ip, last_fsb, 1, 0, NULL, 0, &imap,
-                         &nimaps, NULL, NULL);
+                         &nimaps, NULL);
        if (error) {
                return error;
        }
@@ -558,7 +509,7 @@ xfs_zero_eof(
                nimaps = 1;
                zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
                error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb,
-                                 0, NULL, 0, &imap, &nimaps, NULL, NULL);
+                                 0, NULL, 0, &imap, &nimaps, NULL);
                if (error) {
                        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
                        return error;
@@ -627,7 +578,6 @@ xfs_file_aio_write(
        int                     ioflags = 0;
        xfs_fsize_t             isize, new_size;
        int                     iolock;
-       int                     eventsent = 0;
        size_t                  ocount = 0, count;
        int                     need_i_mutex;
 
@@ -673,33 +623,6 @@ start:
                goto out_unlock_mutex;
        }
 
-       if ((DM_EVENT_ENABLED(ip, DM_EVENT_WRITE) &&
-           !(ioflags & IO_INVIS) && !eventsent)) {
-               int             dmflags = FILP_DELAY_FLAG(file);
-
-               if (need_i_mutex)
-                       dmflags |= DM_FLAGS_IMUX;
-
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               error = XFS_SEND_DATA(ip->i_mount, DM_EVENT_WRITE, ip,
-                                     pos, count, dmflags, &iolock);
-               if (error) {
-                       goto out_unlock_internal;
-               }
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               eventsent = 1;
-
-               /*
-                * The iolock was dropped and reacquired in XFS_SEND_DATA
-                * so we have to recheck the size when appending.
-                * We will only "goto start;" once, since having sent the
-                * event prevents another call to XFS_SEND_DATA, which is
-                * what allows the size to change in the first place.
-                */
-               if ((file->f_flags & O_APPEND) && pos != ip->i_size)
-                       goto start;
-       }
-
        if (ioflags & IO_ISDIRECT) {
                xfs_buftarg_t   *target =
                        XFS_IS_REALTIME_INODE(ip) ?
@@ -830,22 +753,6 @@ write_retry:
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
        }
 
-       if (ret == -ENOSPC &&
-           DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE) && !(ioflags & IO_INVIS)) {
-               xfs_iunlock(ip, iolock);
-               if (need_i_mutex)
-                       mutex_unlock(&inode->i_mutex);
-               error = XFS_SEND_NAMESP(ip->i_mount, DM_EVENT_NOSPACE, ip,
-                               DM_RIGHT_NULL, ip, DM_RIGHT_NULL, NULL, NULL,
-                               0, 0, 0); /* Delay flag intentionally  unused */
-               if (need_i_mutex)
-                       mutex_lock(&inode->i_mutex);
-               xfs_ilock(ip, iolock);
-               if (error)
-                       goto out_unlock_internal;
-               goto start;
-       }
-
        error = -ret;
        if (ret <= 0)
                goto out_unlock_internal;
@@ -1014,9 +921,6 @@ const struct file_operations xfs_file_operations = {
        .open           = xfs_file_open,
        .release        = xfs_file_release,
        .fsync          = xfs_file_fsync,
-#ifdef HAVE_FOP_OPEN_EXEC
-       .open_exec      = xfs_file_open_exec,
-#endif
 };
 
 const struct file_operations xfs_dir_file_operations = {
index b6918d76bc7bbdf9740a07955c0e1694a6bf9825..1f279b012f94be7fd4ef2f5fbf084b89921804c1 100644 (file)
 #include "xfs_inode.h"
 #include "xfs_trace.h"
 
-int  fs_noerr(void) { return 0; }
-int  fs_nosys(void) { return ENOSYS; }
-void fs_noval(void) { return; }
-
 /*
  * note: all filemap functions return negative error codes. These
  * need to be inverted before returning to the xfs core functions.
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.h b/fs/xfs/linux-2.6/xfs_fs_subr.h
deleted file mode 100644 (file)
index 82bb19b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2000,2002,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_FS_SUBR_H__
-#define __XFS_FS_SUBR_H__
-
-extern int  fs_noerr(void);
-extern int  fs_nosys(void);
-extern void fs_noval(void);
-
-#endif /* __XFS_FS_SUBR_H__ */
index e59a8106283069b24bb9fb4b5f0ea5bec92d8ede..237f5ffb2ee8ca067f6dc81ebc38a6de1f7b36ce 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_ioctl.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_rtalloc.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
 #include "xfs_buf_item.h"
@@ -908,7 +899,7 @@ xfs_ioctl_setattr(
        struct xfs_dquot        *olddquot = NULL;
        int                     code;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_ioctl_setattr(ip);
 
        if (mp->m_flags & XFS_MOUNT_RDONLY)
                return XFS_ERROR(EROFS);
@@ -1043,8 +1034,7 @@ xfs_ioctl_setattr(
                }
        }
 
-       xfs_trans_ijoin(tp, ip, lock_flags);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
 
        /*
         * Change file ownership.  Must be the owner or privileged.
@@ -1116,16 +1106,7 @@ xfs_ioctl_setattr(
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
 
-       if (code)
-               return code;
-
-       if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
-               XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
-                               NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
-                               (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
-       }
-
-       return 0;
+       return code;
 
  error_return:
        xfs_qm_dqrele(udqp);
@@ -1301,7 +1282,7 @@ xfs_file_ioctl(
        if (filp->f_mode & FMODE_NOCMTIME)
                ioflags |= IO_INVIS;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_file_ioctl(ip);
 
        switch (cmd) {
        case XFS_IOC_ALLOCSP:
index 52ed49e6465cff0eee12844c13b169583cc1411c..6c83f7f62dc99ca29d5597aad61c97b432ec19ed 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
 #include "xfs_vnode.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -544,7 +540,7 @@ xfs_file_compat_ioctl(
        if (filp->f_mode & FMODE_NOCMTIME)
                ioflags |= IO_INVIS;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_file_compat_ioctl(ip);
 
        switch (cmd) {
        /* No size or alignment issues on any arch */
index 44f0b2de153eb6c4cf77b36c54278f36166d59ba..536b81e63a3d8e397d8e487192f938809ee26923 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_itable.h"
@@ -496,7 +488,7 @@ xfs_vn_getattr(
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_getattr(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
index facfb323a706a914de84de68b504762c82f05d6c..998a9d7fb9c8964d2174f62f935f6fd46b4f2042 100644 (file)
@@ -87,7 +87,6 @@
 #include <xfs_aops.h>
 #include <xfs_super.h>
 #include <xfs_globals.h>
-#include <xfs_fs_subr.h>
 #include <xfs_buf.h>
 
 /*
index 067cafbfc6357fee83a5adbf265e74ab93eeb999..bfd5ac9d1f6f774c49a58588ecc3d6f881bb04aa 100644 (file)
@@ -16,7 +16,6 @@
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "xfs.h"
-#include "xfs_dmapi.h"
 #include "xfs_sb.h"
 #include "xfs_inum.h"
 #include "xfs_log.h"
index 80938c736c2769861327ea10368cd0c20d4ceb51..758df94690edc7ab8663933b289b6c17e82d7289 100644 (file)
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
@@ -43,7 +40,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_fsops.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
@@ -94,7 +90,6 @@ mempool_t *xfs_ioend_pool;
 #define MNTOPT_BARRIER "barrier"       /* use writer barriers for log write and
                                         * unwritten extent conversion */
 #define MNTOPT_NOBARRIER "nobarrier"   /* .. disable */
-#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
 #define MNTOPT_64BITINODE   "inode64"  /* inodes can be allocated anywhere */
 #define MNTOPT_IKEEP   "ikeep"         /* do not free empty inode clusters */
 #define MNTOPT_NOIKEEP "noikeep"       /* free empty inode clusters */
@@ -116,9 +111,6 @@ mempool_t *xfs_ioend_pool;
 #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
 #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
 #define MNTOPT_QUOTANOENF  "qnoenforce"        /* same as uqnoenforce */
-#define MNTOPT_DMAPI   "dmapi"         /* DMI enabled (DMAPI / XDSM) */
-#define MNTOPT_XDSM    "xdsm"          /* DMI enabled (DMAPI / XDSM) */
-#define MNTOPT_DMI     "dmi"           /* DMI enabled (DMAPI / XDSM) */
 #define MNTOPT_DELAYLOG   "delaylog"   /* Delayed loging enabled */
 #define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed loging disabled */
 
@@ -172,15 +164,13 @@ suffix_strtoul(char *s, char **endp, unsigned int base)
 STATIC int
 xfs_parseargs(
        struct xfs_mount        *mp,
-       char                    *options,
-       char                    **mtpt)
+       char                    *options)
 {
        struct super_block      *sb = mp->m_super;
        char                    *this_char, *value, *eov;
        int                     dsunit = 0;
        int                     dswidth = 0;
        int                     iosize = 0;
-       int                     dmapi_implies_ikeep = 1;
        __uint8_t               iosizelog = 0;
 
        /*
@@ -243,15 +233,10 @@ xfs_parseargs(
                        if (!mp->m_logname)
                                return ENOMEM;
                } else if (!strcmp(this_char, MNTOPT_MTPT)) {
-                       if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
-                                       this_char);
-                               return EINVAL;
-                       }
-                       *mtpt = kstrndup(value, MAXNAMELEN, GFP_KERNEL);
-                       if (!*mtpt)
-                               return ENOMEM;
+                       cmn_err(CE_WARN,
+                               "XFS: %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,
@@ -288,8 +273,6 @@ xfs_parseargs(
                        mp->m_flags &= ~XFS_MOUNT_GRPID;
                } else if (!strcmp(this_char, MNTOPT_WSYNC)) {
                        mp->m_flags |= XFS_MOUNT_WSYNC;
-               } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
-                       mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
                } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
                        mp->m_flags |= XFS_MOUNT_NORECOVERY;
                } else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
@@ -329,7 +312,6 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_IKEEP)) {
                        mp->m_flags |= XFS_MOUNT_IKEEP;
                } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) {
-                       dmapi_implies_ikeep = 0;
                        mp->m_flags &= ~XFS_MOUNT_IKEEP;
                } else if (!strcmp(this_char, MNTOPT_LARGEIO)) {
                        mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE;
@@ -370,12 +352,6 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
                        mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
                        mp->m_qflags &= ~XFS_OQUOTA_ENFD;
-               } else if (!strcmp(this_char, MNTOPT_DMAPI)) {
-                       mp->m_flags |= XFS_MOUNT_DMAPI;
-               } else if (!strcmp(this_char, MNTOPT_XDSM)) {
-                       mp->m_flags |= XFS_MOUNT_DMAPI;
-               } else if (!strcmp(this_char, MNTOPT_DMI)) {
-                       mp->m_flags |= XFS_MOUNT_DMAPI;
                } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
                        mp->m_flags |= XFS_MOUNT_DELAYLOG;
                        cmn_err(CE_WARN,
@@ -387,9 +363,11 @@ xfs_parseargs(
                        cmn_err(CE_WARN,
        "XFS: ihashsize no longer used, option is deprecated.");
                } else if (!strcmp(this_char, "osyncisdsync")) {
-                       /* no-op, this is now the default */
                        cmn_err(CE_WARN,
-       "XFS: osyncisdsync is now the default, option is deprecated.");
+       "XFS: 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.");
                } else if (!strcmp(this_char, "irixsgid")) {
                        cmn_err(CE_WARN,
        "XFS: irixsgid is now a sysctl(2) variable, option is deprecated.");
@@ -430,12 +408,6 @@ xfs_parseargs(
                return EINVAL;
        }
 
-       if ((mp->m_flags & XFS_MOUNT_DMAPI) && (!*mtpt || *mtpt[0] == '\0')) {
-               printk("XFS: %s option needs the mount point option as well\n",
-                       MNTOPT_DMAPI);
-               return EINVAL;
-       }
-
        if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
                cmn_err(CE_WARN,
                        "XFS: sunit and swidth must be specified together");
@@ -449,18 +421,6 @@ xfs_parseargs(
                return EINVAL;
        }
 
-       /*
-        * Applications using DMI filesystems often expect the
-        * inode generation number to be monotonically increasing.
-        * If we delete inode chunks we break this assumption, so
-        * keep unused inode chunks on disk for DMI filesystems
-        * until we come up with a better solution.
-        * Note that if "ikeep" or "noikeep" mount options are
-        * supplied, then they are honored.
-        */
-       if ((mp->m_flags & XFS_MOUNT_DMAPI) && dmapi_implies_ikeep)
-               mp->m_flags |= XFS_MOUNT_IKEEP;
-
 done:
        if (!(mp->m_flags & XFS_MOUNT_NOALIGN)) {
                /*
@@ -539,10 +499,8 @@ xfs_showargs(
                { XFS_MOUNT_SWALLOC,            "," MNTOPT_SWALLOC },
                { XFS_MOUNT_NOUUID,             "," MNTOPT_NOUUID },
                { XFS_MOUNT_NORECOVERY,         "," MNTOPT_NORECOVERY },
-               { XFS_MOUNT_OSYNCISOSYNC,       "," MNTOPT_OSYNCISOSYNC },
                { XFS_MOUNT_ATTR2,              "," MNTOPT_ATTR2 },
                { XFS_MOUNT_FILESTREAMS,        "," MNTOPT_FILESTREAM },
-               { XFS_MOUNT_DMAPI,              "," MNTOPT_DMAPI },
                { XFS_MOUNT_GRPID,              "," MNTOPT_GRPID },
                { XFS_MOUNT_DELAYLOG,           "," MNTOPT_DELAYLOG },
                { 0, NULL }
@@ -947,7 +905,7 @@ xfs_fs_destroy_inode(
 {
        struct xfs_inode        *ip = XFS_I(inode);
 
-       xfs_itrace_entry(ip);
+       trace_xfs_destroy_inode(ip);
 
        XFS_STATS_INC(vn_reclaim);
 
@@ -1063,10 +1021,8 @@ xfs_log_inode(
         * an inode in another recent transaction.  So we play it safe and
         * fire off the transaction anyway.
         */
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       xfs_trans_set_sync(tp);
        error = xfs_trans_commit(tp, 0);
        xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
 
@@ -1082,27 +1038,18 @@ xfs_fs_write_inode(
        struct xfs_mount        *mp = ip->i_mount;
        int                     error = EAGAIN;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_write_inode(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
        if (wbc->sync_mode == WB_SYNC_ALL) {
                /*
-                * Make sure the inode has hit stable storage.  By using the
-                * log and the fsync transactions we reduce the IOs we have
-                * to do here from two (log and inode) to just the log.
-                *
-                * Note: We still need to do a delwri write of the inode after
-                * this to flush it to the backing buffer so that bulkstat
-                * works properly if this is the first time the inode has been
-                * written.  Because we hold the ilock atomically over the
-                * transaction commit and the inode flush we are guaranteed
-                * that the inode is not pinned when it returns. If the flush
-                * lock is already held, then the inode has already been
-                * flushed once and we don't need to flush it again.  Hence
-                * the code will only flush the inode if it isn't already
-                * being flushed.
+                * Make sure the inode has made it it into the log.  Instead
+                * of forcing it all the way to stable storage using a
+                * synchronous transaction we let the log force inside the
+                * ->sync_fs call do that for thus, which reduces the number
+                * of synchronous log foces dramatically.
                 */
                xfs_ioend_wait(ip);
                xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -1116,27 +1063,29 @@ xfs_fs_write_inode(
                 * We make this non-blocking if the inode is contended, return
                 * EAGAIN to indicate to the caller that they did not succeed.
                 * This prevents the flush path from blocking on inodes inside
-                * another operation right now, they get caught later by xfs_sync.
+                * another operation right now, they get caught later by
+                * xfs_sync.
                 */
                if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
                        goto out;
-       }
 
-       if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
-               goto out_unlock;
+               if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
+                       goto out_unlock;
 
-       /*
-        * Now we have the flush lock and the inode is not pinned, we can check
-        * if the inode is really clean as we know that there are no pending
-        * transaction completions, it is not waiting on the delayed write
-        * queue and there is no IO in progress.
-        */
-       if (xfs_inode_clean(ip)) {
-               xfs_ifunlock(ip);
-               error = 0;
-               goto out_unlock;
+               /*
+                * Now we have the flush lock and the inode is not pinned, we
+                * can check if the inode is really clean as we know that
+                * there are no pending transaction completions, it is not
+                * waiting on the delayed write queue and there is no IO in
+                * progress.
+                */
+               if (xfs_inode_clean(ip)) {
+                       xfs_ifunlock(ip);
+                       error = 0;
+                       goto out_unlock;
+               }
+               error = xfs_iflush(ip, 0);
        }
-       error = xfs_iflush(ip, 0);
 
  out_unlock:
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@ -1156,7 +1105,8 @@ xfs_fs_clear_inode(
 {
        xfs_inode_t             *ip = XFS_I(inode);
 
-       xfs_itrace_entry(ip);
+       trace_xfs_clear_inode(ip);
+
        XFS_STATS_INC(vn_rele);
        XFS_STATS_INC(vn_remove);
        XFS_STATS_DEC(vn_active);
@@ -1193,22 +1143,13 @@ xfs_fs_put_super(
 {
        struct xfs_mount        *mp = XFS_M(sb);
 
+       /*
+        * Unregister the memory shrinker before we tear down the mount
+        * structure so we don't have memory reclaim racing with us here.
+        */
+       xfs_inode_shrinker_unregister(mp);
        xfs_syncd_stop(mp);
 
-       if (!(sb->s_flags & MS_RDONLY)) {
-               /*
-                * XXX(hch): this should be SYNC_WAIT.
-                *
-                * Or more likely not needed at all because the VFS is already
-                * calling ->sync_fs after shutting down all filestem
-                * operations and just before calling ->put_super.
-                */
-               xfs_sync_data(mp, 0);
-               xfs_sync_attr(mp, 0);
-       }
-
-       XFS_SEND_PREUNMOUNT(mp);
-
        /*
         * Blow away any referenced inode in the filestreams cache.
         * This can and will cause log traffic as inodes go inactive
@@ -1218,14 +1159,10 @@ xfs_fs_put_super(
 
        XFS_bflush(mp->m_ddev_targp);
 
-       XFS_SEND_UNMOUNT(mp);
-
        xfs_unmountfs(mp);
        xfs_freesb(mp);
-       xfs_inode_shrinker_unregister(mp);
        xfs_icsb_destroy_counters(mp);
        xfs_close_devices(mp);
-       xfs_dmops_put(mp);
        xfs_free_fsname(mp);
        kfree(mp);
 }
@@ -1543,7 +1480,6 @@ xfs_fs_fill_super(
        struct inode            *root;
        struct xfs_mount        *mp = NULL;
        int                     flags = 0, error = ENOMEM;
-       char                    *mtpt = NULL;
 
        mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL);
        if (!mp)
@@ -1559,7 +1495,7 @@ xfs_fs_fill_super(
        mp->m_super = sb;
        sb->s_fs_info = mp;
 
-       error = xfs_parseargs(mp, (char *)data, &mtpt);
+       error = xfs_parseargs(mp, (char *)data);
        if (error)
                goto out_free_fsname;
 
@@ -1571,16 +1507,12 @@ xfs_fs_fill_super(
 #endif
        sb->s_op = &xfs_super_operations;
 
-       error = xfs_dmops_get(mp);
-       if (error)
-               goto out_free_fsname;
-
        if (silent)
                flags |= XFS_MFSI_QUIET;
 
        error = xfs_open_devices(mp);
        if (error)
-               goto out_put_dmops;
+               goto out_free_fsname;
 
        if (xfs_icsb_init_counters(mp))
                mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
@@ -1608,8 +1540,6 @@ xfs_fs_fill_super(
        if (error)
                goto out_filestream_unmount;
 
-       XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, mtpt, mp->m_fsname);
-
        sb->s_magic = XFS_SB_MAGIC;
        sb->s_blocksize = mp->m_sb.sb_blocksize;
        sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1;
@@ -1638,7 +1568,6 @@ xfs_fs_fill_super(
 
        xfs_inode_shrinker_register(mp);
 
-       kfree(mtpt);
        return 0;
 
  out_filestream_unmount:
@@ -1648,11 +1577,8 @@ xfs_fs_fill_super(
  out_destroy_counters:
        xfs_icsb_destroy_counters(mp);
        xfs_close_devices(mp);
- out_put_dmops:
-       xfs_dmops_put(mp);
  out_free_fsname:
        xfs_free_fsname(mp);
-       kfree(mtpt);
        kfree(mp);
  out:
        return -error;
@@ -1759,6 +1685,12 @@ xfs_init_zones(void)
        if (!xfs_trans_zone)
                goto out_destroy_ifork_zone;
 
+       xfs_log_item_desc_zone =
+               kmem_zone_init(sizeof(struct xfs_log_item_desc),
+                              "xfs_log_item_desc");
+       if (!xfs_log_item_desc_zone)
+               goto out_destroy_trans_zone;
+
        /*
         * The size of the zone allocated buf log item is the maximum
         * size possible under XFS.  This wastes a little bit of memory,
@@ -1768,7 +1700,7 @@ xfs_init_zones(void)
                                (((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) /
                                  NBWORD) * sizeof(int))), "xfs_buf_item");
        if (!xfs_buf_item_zone)
-               goto out_destroy_trans_zone;
+               goto out_destroy_log_item_desc_zone;
 
        xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) +
                        ((XFS_EFD_MAX_FAST_EXTENTS - 1) *
@@ -1805,6 +1737,8 @@ xfs_init_zones(void)
        kmem_zone_destroy(xfs_efd_zone);
  out_destroy_buf_item_zone:
        kmem_zone_destroy(xfs_buf_item_zone);
+ out_destroy_log_item_desc_zone:
+       kmem_zone_destroy(xfs_log_item_desc_zone);
  out_destroy_trans_zone:
        kmem_zone_destroy(xfs_trans_zone);
  out_destroy_ifork_zone:
@@ -1835,6 +1769,7 @@ xfs_destroy_zones(void)
        kmem_zone_destroy(xfs_efi_zone);
        kmem_zone_destroy(xfs_efd_zone);
        kmem_zone_destroy(xfs_buf_item_zone);
+       kmem_zone_destroy(xfs_log_item_desc_zone);
        kmem_zone_destroy(xfs_trans_zone);
        kmem_zone_destroy(xfs_ifork_zone);
        kmem_zone_destroy(xfs_dabuf_zone);
index 519618e9279eda5c4d81ca398679d835ff77df28..1ef4a4d2d99796caf7ea1be05fc1becb56846f16 100644 (file)
@@ -56,12 +56,6 @@ extern void xfs_qm_exit(void);
 # define XFS_BIGFS_STRING
 #endif
 
-#ifdef CONFIG_XFS_DMAPI
-# define XFS_DMAPI_STRING      "dmapi support, "
-#else
-# define XFS_DMAPI_STRING
-#endif
-
 #ifdef DEBUG
 # define XFS_DBG_STRING                "debug"
 #else
@@ -72,7 +66,6 @@ extern void xfs_qm_exit(void);
                                XFS_SECURITY_STRING \
                                XFS_REALTIME_STRING \
                                XFS_BIGFS_STRING \
-                               XFS_DMAPI_STRING \
                                XFS_DBG_STRING /* DBG must be last */
 
 struct xfs_inode;
index a51a07c3a70cfa8b5514add3dae137402bbc56b6..dfcbd98d15997e62e7d8a433fa71e5b8a9912609 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_inode.h"
 #include "xfs_dinode.h"
 #include "xfs_error.h"
-#include "xfs_mru_cache.h"
 #include "xfs_filestream.h"
 #include "xfs_vnodeops.h"
-#include "xfs_utils.h"
-#include "xfs_buf_item.h"
 #include "xfs_inode_item.h"
-#include "xfs_rw.h"
 #include "xfs_quota.h"
 #include "xfs_trace.h"
 
@@ -319,7 +308,7 @@ xfs_sync_inode_attr(
 /*
  * Write out pagecache data for the whole filesystem.
  */
-int
+STATIC int
 xfs_sync_data(
        struct xfs_mount        *mp,
        int                     flags)
@@ -340,7 +329,7 @@ xfs_sync_data(
 /*
  * Write out inode metadata (attributes) for the whole filesystem.
  */
-int
+STATIC int
 xfs_sync_attr(
        struct xfs_mount        *mp,
        int                     flags)
@@ -373,8 +362,7 @@ xfs_commit_dummy_trans(
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        error = xfs_trans_commit(tp, 0);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -867,7 +855,36 @@ out:
 reclaim:
        xfs_ifunlock(ip);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       xfs_ireclaim(ip);
+
+       XFS_STATS_INC(xs_ig_reclaims);
+       /*
+        * Remove the inode from the per-AG radix tree.
+        *
+        * Because radix_tree_delete won't complain even if the item was never
+        * added to the tree assert that it's been there before to catch
+        * problems with the inode life time early on.
+        */
+       write_lock(&pag->pag_ici_lock);
+       if (!radix_tree_delete(&pag->pag_ici_root,
+                               XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino)))
+               ASSERT(0);
+       write_unlock(&pag->pag_ici_lock);
+
+       /*
+        * Here we do an (almost) spurious inode lock in order to coordinate
+        * with inode cache radix tree lookups.  This is because the lookup
+        * can reference the inodes in the cache without taking references.
+        *
+        * We make that OK here by ensuring that we wait until the inode is
+        * unlocked after the lookup before we go ahead and free it.  We get
+        * both the ilock and the iolock because the code may need to drop the
+        * ilock one but will still hold the iolock.
+        */
+       xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_qm_dqdetach(ip);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+
+       xfs_inode_free(ip);
        return error;
 
 }
index e28139aaa4aa42c6085100856345e0156a33eef3..fe78726196f8200cd777298e82560f12f180e23c 100644 (file)
@@ -35,9 +35,6 @@ typedef struct xfs_sync_work {
 int xfs_syncd_init(struct xfs_mount *mp);
 void xfs_syncd_stop(struct xfs_mount *mp);
 
-int xfs_sync_attr(struct xfs_mount *mp, int flags);
-int xfs_sync_data(struct xfs_mount *mp, int flags);
-
 int xfs_quiesce_data(struct xfs_mount *mp);
 void xfs_quiesce_attr(struct xfs_mount *mp);
 
index d12be8470cbac741dcdc42ba402cb2e228dd93a2..88d25d4aa56ec34b0a9039af8d52d567c478a429 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_ialloc.h"
 #include "xfs_itable.h"
index 302820690904d1eff4de201ca97ca97a5fad4c9d..c657cdca2cd2648ac173332556bc371ffb577847 100644 (file)
@@ -317,8 +317,6 @@ DEFINE_BUF_EVENT(xfs_buf_init);
 DEFINE_BUF_EVENT(xfs_buf_free);
 DEFINE_BUF_EVENT(xfs_buf_hold);
 DEFINE_BUF_EVENT(xfs_buf_rele);
-DEFINE_BUF_EVENT(xfs_buf_pin);
-DEFINE_BUF_EVENT(xfs_buf_unpin);
 DEFINE_BUF_EVENT(xfs_buf_iodone);
 DEFINE_BUF_EVENT(xfs_buf_iorequest);
 DEFINE_BUF_EVENT(xfs_buf_bawrite);
@@ -541,7 +539,7 @@ DEFINE_LOCK_EVENT(xfs_ilock_nowait);
 DEFINE_LOCK_EVENT(xfs_ilock_demote);
 DEFINE_LOCK_EVENT(xfs_iunlock);
 
-DECLARE_EVENT_CLASS(xfs_iget_class,
+DECLARE_EVENT_CLASS(xfs_inode_class,
        TP_PROTO(struct xfs_inode *ip),
        TP_ARGS(ip),
        TP_STRUCT__entry(
@@ -557,16 +555,38 @@ DECLARE_EVENT_CLASS(xfs_iget_class,
                  __entry->ino)
 )
 
-#define DEFINE_IGET_EVENT(name) \
-DEFINE_EVENT(xfs_iget_class, name, \
+#define DEFINE_INODE_EVENT(name) \
+DEFINE_EVENT(xfs_inode_class, name, \
        TP_PROTO(struct xfs_inode *ip), \
        TP_ARGS(ip))
-DEFINE_IGET_EVENT(xfs_iget_skip);
-DEFINE_IGET_EVENT(xfs_iget_reclaim);
-DEFINE_IGET_EVENT(xfs_iget_found);
-DEFINE_IGET_EVENT(xfs_iget_alloc);
-
-DECLARE_EVENT_CLASS(xfs_inode_class,
+DEFINE_INODE_EVENT(xfs_iget_skip);
+DEFINE_INODE_EVENT(xfs_iget_reclaim);
+DEFINE_INODE_EVENT(xfs_iget_reclaim_fail);
+DEFINE_INODE_EVENT(xfs_iget_hit);
+DEFINE_INODE_EVENT(xfs_iget_miss);
+
+DEFINE_INODE_EVENT(xfs_getattr);
+DEFINE_INODE_EVENT(xfs_setattr);
+DEFINE_INODE_EVENT(xfs_readlink);
+DEFINE_INODE_EVENT(xfs_alloc_file_space);
+DEFINE_INODE_EVENT(xfs_free_file_space);
+DEFINE_INODE_EVENT(xfs_readdir);
+#ifdef CONFIG_XFS_POSIX_ACL
+DEFINE_INODE_EVENT(xfs_check_acl);
+#endif
+DEFINE_INODE_EVENT(xfs_vm_bmap);
+DEFINE_INODE_EVENT(xfs_file_ioctl);
+DEFINE_INODE_EVENT(xfs_file_compat_ioctl);
+DEFINE_INODE_EVENT(xfs_ioctl_setattr);
+DEFINE_INODE_EVENT(xfs_file_fsync);
+DEFINE_INODE_EVENT(xfs_destroy_inode);
+DEFINE_INODE_EVENT(xfs_write_inode);
+DEFINE_INODE_EVENT(xfs_clear_inode);
+
+DEFINE_INODE_EVENT(xfs_dquot_dqalloc);
+DEFINE_INODE_EVENT(xfs_dquot_dqdetach);
+
+DECLARE_EVENT_CLASS(xfs_iref_class,
        TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip),
        TP_ARGS(ip, caller_ip),
        TP_STRUCT__entry(
@@ -591,20 +611,71 @@ DECLARE_EVENT_CLASS(xfs_inode_class,
                  (char *)__entry->caller_ip)
 )
 
-#define DEFINE_INODE_EVENT(name) \
-DEFINE_EVENT(xfs_inode_class, name, \
+#define DEFINE_IREF_EVENT(name) \
+DEFINE_EVENT(xfs_iref_class, name, \
        TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip), \
        TP_ARGS(ip, caller_ip))
-DEFINE_INODE_EVENT(xfs_ihold);
-DEFINE_INODE_EVENT(xfs_irele);
-DEFINE_INODE_EVENT(xfs_inode_pin);
-DEFINE_INODE_EVENT(xfs_inode_unpin);
-DEFINE_INODE_EVENT(xfs_inode_unpin_nowait);
+DEFINE_IREF_EVENT(xfs_ihold);
+DEFINE_IREF_EVENT(xfs_irele);
+DEFINE_IREF_EVENT(xfs_inode_pin);
+DEFINE_IREF_EVENT(xfs_inode_unpin);
+DEFINE_IREF_EVENT(xfs_inode_unpin_nowait);
+
+DECLARE_EVENT_CLASS(xfs_namespace_class,
+       TP_PROTO(struct xfs_inode *dp, struct xfs_name *name),
+       TP_ARGS(dp, name),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_ino_t, dp_ino)
+               __dynamic_array(char, name, name->len)
+       ),
+       TP_fast_assign(
+               __entry->dev = VFS_I(dp)->i_sb->s_dev;
+               __entry->dp_ino = dp->i_ino;
+               memcpy(__get_str(name), name->name, name->len);
+       ),
+       TP_printk("dev %d:%d dp ino 0x%llx name %s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->dp_ino,
+                 __get_str(name))
+)
 
-/* the old xfs_itrace_entry tracer - to be replaced by s.th. in the VFS */
-DEFINE_INODE_EVENT(xfs_inode);
-#define xfs_itrace_entry(ip)    \
-       trace_xfs_inode(ip, _THIS_IP_)
+#define DEFINE_NAMESPACE_EVENT(name) \
+DEFINE_EVENT(xfs_namespace_class, name, \
+       TP_PROTO(struct xfs_inode *dp, struct xfs_name *name), \
+       TP_ARGS(dp, name))
+DEFINE_NAMESPACE_EVENT(xfs_remove);
+DEFINE_NAMESPACE_EVENT(xfs_link);
+DEFINE_NAMESPACE_EVENT(xfs_lookup);
+DEFINE_NAMESPACE_EVENT(xfs_create);
+DEFINE_NAMESPACE_EVENT(xfs_symlink);
+
+TRACE_EVENT(xfs_rename,
+       TP_PROTO(struct xfs_inode *src_dp, struct xfs_inode *target_dp,
+                struct xfs_name *src_name, struct xfs_name *target_name),
+       TP_ARGS(src_dp, target_dp, src_name, target_name),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_ino_t, src_dp_ino)
+               __field(xfs_ino_t, target_dp_ino)
+               __dynamic_array(char, src_name, src_name->len)
+               __dynamic_array(char, target_name, target_name->len)
+       ),
+       TP_fast_assign(
+               __entry->dev = VFS_I(src_dp)->i_sb->s_dev;
+               __entry->src_dp_ino = src_dp->i_ino;
+               __entry->target_dp_ino = target_dp->i_ino;
+               memcpy(__get_str(src_name), src_name->name, src_name->len);
+               memcpy(__get_str(target_name), target_name->name, target_name->len);
+       ),
+       TP_printk("dev %d:%d src dp ino 0x%llx target dp ino 0x%llx"
+                 " src name %s target name %s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->src_dp_ino,
+                 __entry->target_dp_ino,
+                 __get_str(src_name),
+                 __get_str(target_name))
+)
 
 DECLARE_EVENT_CLASS(xfs_dquot_class,
        TP_PROTO(struct xfs_dquot *dqp),
@@ -684,9 +755,6 @@ DEFINE_DQUOT_EVENT(xfs_dqrele);
 DEFINE_DQUOT_EVENT(xfs_dqflush);
 DEFINE_DQUOT_EVENT(xfs_dqflush_force);
 DEFINE_DQUOT_EVENT(xfs_dqflush_done);
-/* not really iget events, but we re-use the format */
-DEFINE_IGET_EVENT(xfs_dquot_dqalloc);
-DEFINE_IGET_EVENT(xfs_dquot_dqdetach);
 
 DECLARE_EVENT_CLASS(xfs_loggrant_class,
        TP_PROTO(struct log *log, struct xlog_ticket *tic),
@@ -834,33 +902,29 @@ DECLARE_EVENT_CLASS(xfs_page_class,
                __field(loff_t, size)
                __field(unsigned long, offset)
                __field(int, delalloc)
-               __field(int, unmapped)
                __field(int, unwritten)
        ),
        TP_fast_assign(
-               int delalloc = -1, unmapped = -1, unwritten = -1;
+               int delalloc = -1, unwritten = -1;
 
                if (page_has_buffers(page))
-                       xfs_count_page_state(page, &delalloc,
-                                            &unmapped, &unwritten);
+                       xfs_count_page_state(page, &delalloc, &unwritten);
                __entry->dev = inode->i_sb->s_dev;
                __entry->ino = XFS_I(inode)->i_ino;
                __entry->pgoff = page_offset(page);
                __entry->size = i_size_read(inode);
                __entry->offset = off;
                __entry->delalloc = delalloc;
-               __entry->unmapped = unmapped;
                __entry->unwritten = unwritten;
        ),
        TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx "
-                 "delalloc %d unmapped %d unwritten %d",
+                 "delalloc %d unwritten %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __entry->pgoff,
                  __entry->size,
                  __entry->offset,
                  __entry->delalloc,
-                 __entry->unmapped,
                  __entry->unwritten)
 )
 
index 585e7633dfc75b176df3989186628385b857bf8e..e1a2f6800e01da339586080d23b6a760747a4725 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_itable.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -64,8 +54,6 @@
    flush lock - ditto.
 */
 
-STATIC void            xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
-
 #ifdef DEBUG
 xfs_buftarg_t *xfs_dqerror_target;
 int xfs_do_dqerror;
@@ -390,21 +378,14 @@ xfs_qm_dqalloc(
                return (ESRCH);
        }
 
-       /*
-        * xfs_trans_commit normally decrements the vnode ref count
-        * when it unlocks the inode. Since we want to keep the quota
-        * inode around, we bump the vnode ref count now.
-        */
-       IHOLD(quotip);
-
-       xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, quotip, XFS_ILOCK_EXCL);
        nmaps = 1;
        if ((error = xfs_bmapi(tp, quotip,
                              offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
                              XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
                              &firstblock,
                              XFS_QM_DQALLOC_SPACE_RES(mp),
-                             &map, &nmaps, &flist, NULL))) {
+                             &map, &nmaps, &flist))) {
                goto error0;
        }
        ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
@@ -520,7 +501,7 @@ xfs_qm_dqtobp(
                error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
                                  XFS_DQUOT_CLUSTER_SIZE_FSB,
                                  XFS_BMAPI_METADATA,
-                                 NULL, 0, &map, &nmaps, NULL, NULL);
+                                 NULL, 0, &map, &nmaps, NULL);
 
                xfs_iunlock(quotip, XFS_ILOCK_SHARED);
                if (error)
@@ -1141,6 +1122,46 @@ xfs_qm_dqrele(
        xfs_qm_dqput(dqp);
 }
 
+/*
+ * This is the dquot flushing I/O completion routine.  It is called
+ * from interrupt level when the buffer containing the dquot is
+ * flushed to disk.  It is responsible for removing the dquot logitem
+ * from the AIL if it has not been re-logged, and unlocking the dquot's
+ * flush lock. This behavior is very similar to that of inodes..
+ */
+STATIC void
+xfs_qm_dqflush_done(
+       struct xfs_buf          *bp,
+       struct xfs_log_item     *lip)
+{
+       xfs_dq_logitem_t        *qip = (struct xfs_dq_logitem *)lip;
+       xfs_dquot_t             *dqp = qip->qli_dquot;
+       struct xfs_ail          *ailp = lip->li_ailp;
+
+       /*
+        * We only want to pull the item from the AIL if its
+        * location in the log has not changed since we started the flush.
+        * Thus, we only bother if the dquot's lsn has
+        * not changed. First we check the lsn outside the lock
+        * since it's cheaper, and then we recheck while
+        * holding the lock before removing the dquot from the AIL.
+        */
+       if ((lip->li_flags & XFS_LI_IN_AIL) &&
+           lip->li_lsn == qip->qli_flush_lsn) {
+
+               /* xfs_trans_ail_delete() drops the AIL lock. */
+               spin_lock(&ailp->xa_lock);
+               if (lip->li_lsn == qip->qli_flush_lsn)
+                       xfs_trans_ail_delete(ailp, lip);
+               else
+                       spin_unlock(&ailp->xa_lock);
+       }
+
+       /*
+        * Release the dq's flush lock since we're done with it.
+        */
+       xfs_dqfunlock(dqp);
+}
 
 /*
  * Write a modified dquot to disk.
@@ -1222,8 +1243,9 @@ xfs_qm_dqflush(
         * Attach an iodone routine so that we can remove this dquot from the
         * AIL and release the flush lock once the dquot is synced to disk.
         */
-       xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
-                             xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
+       xfs_buf_attach_iodone(bp, xfs_qm_dqflush_done,
+                                 &dqp->q_logitem.qli_item);
+
        /*
         * If the buffer is pinned then push on the log so we won't
         * get stuck waiting in the write for too long.
@@ -1247,50 +1269,6 @@ xfs_qm_dqflush(
 
 }
 
-/*
- * This is the dquot flushing I/O completion routine.  It is called
- * from interrupt level when the buffer containing the dquot is
- * flushed to disk.  It is responsible for removing the dquot logitem
- * from the AIL if it has not been re-logged, and unlocking the dquot's
- * flush lock. This behavior is very similar to that of inodes..
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_dqflush_done(
-       xfs_buf_t               *bp,
-       xfs_dq_logitem_t        *qip)
-{
-       xfs_dquot_t             *dqp;
-       struct xfs_ail          *ailp;
-
-       dqp = qip->qli_dquot;
-       ailp = qip->qli_item.li_ailp;
-
-       /*
-        * We only want to pull the item from the AIL if its
-        * location in the log has not changed since we started the flush.
-        * Thus, we only bother if the dquot's lsn has
-        * not changed. First we check the lsn outside the lock
-        * since it's cheaper, and then we recheck while
-        * holding the lock before removing the dquot from the AIL.
-        */
-       if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-           qip->qli_item.li_lsn == qip->qli_flush_lsn) {
-
-               /* xfs_trans_ail_delete() drops the AIL lock. */
-               spin_lock(&ailp->xa_lock);
-               if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
-                       xfs_trans_ail_delete(ailp, (xfs_log_item_t*)qip);
-               else
-                       spin_unlock(&ailp->xa_lock);
-       }
-
-       /*
-        * Release the dq's flush lock since we're done with it.
-        */
-       xfs_dqfunlock(dqp);
-}
-
 int
 xfs_qm_dqlock_nowait(
        xfs_dquot_t *dqp)
index 8d89a24ae3244d1cd2ce75bcf22d37429d5f2ced..2a1f3dc10a02dba4f401a326fd72f07bd40212af 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_itable.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
 #include "xfs_qm.h"
 
+static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_dq_logitem, qli_item);
+}
+
 /*
  * returns the number of iovecs needed to log the given dquot item.
  */
-/* ARGSUSED */
 STATIC uint
 xfs_qm_dquot_logitem_size(
-       xfs_dq_logitem_t        *logitem)
+       struct xfs_log_item     *lip)
 {
        /*
         * we need only two iovecs, one for the format, one for the real thing
         */
-       return (2);
+       return 2;
 }
 
 /*
@@ -66,22 +60,21 @@ xfs_qm_dquot_logitem_size(
  */
 STATIC void
 xfs_qm_dquot_logitem_format(
-       xfs_dq_logitem_t        *logitem,
-       xfs_log_iovec_t         *logvec)
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *logvec)
 {
-       ASSERT(logitem);
-       ASSERT(logitem->qli_dquot);
+       struct xfs_dq_logitem   *qlip = DQUOT_ITEM(lip);
 
-       logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
+       logvec->i_addr = &qlip->qli_format;
        logvec->i_len  = sizeof(xfs_dq_logformat_t);
        logvec->i_type = XLOG_REG_TYPE_QFORMAT;
        logvec++;
-       logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
+       logvec->i_addr = &qlip->qli_dquot->q_core;
        logvec->i_len  = sizeof(xfs_disk_dquot_t);
        logvec->i_type = XLOG_REG_TYPE_DQUOT;
 
-       ASSERT(2 == logitem->qli_item.li_desc->lid_size);
-       logitem->qli_format.qlf_size = 2;
+       ASSERT(2 == lip->li_desc->lid_size);
+       qlip->qli_format.qlf_size = 2;
 
 }
 
@@ -90,9 +83,9 @@ xfs_qm_dquot_logitem_format(
  */
 STATIC void
 xfs_qm_dquot_logitem_pin(
-       xfs_dq_logitem_t *logitem)
+       struct xfs_log_item     *lip)
 {
-       xfs_dquot_t *dqp = logitem->qli_dquot;
+       struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
        atomic_inc(&dqp->q_pincount);
@@ -104,27 +97,18 @@ xfs_qm_dquot_logitem_pin(
  * dquot must have been previously pinned with a call to
  * xfs_qm_dquot_logitem_pin().
  */
-/* ARGSUSED */
 STATIC void
 xfs_qm_dquot_logitem_unpin(
-       xfs_dq_logitem_t *logitem)
+       struct xfs_log_item     *lip,
+       int                     remove)
 {
-       xfs_dquot_t *dqp = logitem->qli_dquot;
+       struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 
        ASSERT(atomic_read(&dqp->q_pincount) > 0);
        if (atomic_dec_and_test(&dqp->q_pincount))
                wake_up(&dqp->q_pinwait);
 }
 
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_unpin_remove(
-       xfs_dq_logitem_t *logitem,
-       xfs_trans_t      *tp)
-{
-       xfs_qm_dquot_logitem_unpin(logitem);
-}
-
 /*
  * Given the logitem, this writes the corresponding dquot entry to disk
  * asynchronously. This is called with the dquot entry securely locked;
@@ -133,12 +117,10 @@ xfs_qm_dquot_logitem_unpin_remove(
  */
 STATIC void
 xfs_qm_dquot_logitem_push(
-       xfs_dq_logitem_t        *logitem)
+       struct xfs_log_item     *lip)
 {
-       xfs_dquot_t     *dqp;
-       int             error;
-
-       dqp = logitem->qli_dquot;
+       struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
+       int                     error;
 
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
        ASSERT(!completion_done(&dqp->q_flush));
@@ -160,27 +142,25 @@ xfs_qm_dquot_logitem_push(
        xfs_dqunlock(dqp);
 }
 
-/*ARGSUSED*/
 STATIC xfs_lsn_t
 xfs_qm_dquot_logitem_committed(
-       xfs_dq_logitem_t        *l,
+       struct xfs_log_item     *lip,
        xfs_lsn_t               lsn)
 {
        /*
         * We always re-log the entire dquot when it becomes dirty,
         * so, the latest copy _is_ the only one that matters.
         */
-       return (lsn);
+       return lsn;
 }
 
-
 /*
  * This is called to wait for the given dquot to be unpinned.
  * Most of these pin/unpin routines are plagiarized from inode code.
  */
 void
 xfs_qm_dqunpin_wait(
-       xfs_dquot_t     *dqp)
+       struct xfs_dquot        *dqp)
 {
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
        if (atomic_read(&dqp->q_pincount) == 0)
@@ -206,13 +186,12 @@ xfs_qm_dqunpin_wait(
  */
 STATIC void
 xfs_qm_dquot_logitem_pushbuf(
-       xfs_dq_logitem_t    *qip)
+       struct xfs_log_item     *lip)
 {
-       xfs_dquot_t     *dqp;
-       xfs_mount_t     *mp;
-       xfs_buf_t       *bp;
+       struct xfs_dq_logitem   *qlip = DQUOT_ITEM(lip);
+       struct xfs_dquot        *dqp = qlip->qli_dquot;
+       struct xfs_buf          *bp;
 
-       dqp = qip->qli_dquot;
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
        /*
@@ -220,22 +199,20 @@ xfs_qm_dquot_logitem_pushbuf(
         * inode flush completed and the inode was taken off the AIL.
         * So, just get out.
         */
-       if (completion_done(&dqp->q_flush)  ||
-           ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
+       if (completion_done(&dqp->q_flush) ||
+           !(lip->li_flags & XFS_LI_IN_AIL)) {
                xfs_dqunlock(dqp);
                return;
        }
-       mp = dqp->q_mount;
-       bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
-                       mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
+
+       bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
+                       dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
        xfs_dqunlock(dqp);
        if (!bp)
                return;
        if (XFS_BUF_ISDELAYWRITE(bp))
                xfs_buf_delwri_promote(bp);
        xfs_buf_relse(bp);
-       return;
-
 }
 
 /*
@@ -250,15 +227,14 @@ xfs_qm_dquot_logitem_pushbuf(
  */
 STATIC uint
 xfs_qm_dquot_logitem_trylock(
-       xfs_dq_logitem_t        *qip)
+       struct xfs_log_item     *lip)
 {
-       xfs_dquot_t             *dqp;
+       struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 
-       dqp = qip->qli_dquot;
        if (atomic_read(&dqp->q_pincount) > 0)
                return XFS_ITEM_PINNED;
 
-       if (! xfs_qm_dqlock_nowait(dqp))
+       if (!xfs_qm_dqlock_nowait(dqp))
                return XFS_ITEM_LOCKED;
 
        if (!xfs_dqflock_nowait(dqp)) {
@@ -269,11 +245,10 @@ xfs_qm_dquot_logitem_trylock(
                return XFS_ITEM_PUSHBUF;
        }
 
-       ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
+       ASSERT(lip->li_flags & XFS_LI_IN_AIL);
        return XFS_ITEM_SUCCESS;
 }
 
-
 /*
  * Unlock the dquot associated with the log item.
  * Clear the fields of the dquot and dquot log item that
@@ -282,12 +257,10 @@ xfs_qm_dquot_logitem_trylock(
  */
 STATIC void
 xfs_qm_dquot_logitem_unlock(
-       xfs_dq_logitem_t    *ql)
+       struct xfs_log_item     *lip)
 {
-       xfs_dquot_t     *dqp;
+       struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 
-       ASSERT(ql != NULL);
-       dqp = ql->qli_dquot;
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
        /*
@@ -304,43 +277,32 @@ xfs_qm_dquot_logitem_unlock(
        xfs_dqunlock(dqp);
 }
 
-
 /*
  * this needs to stamp an lsn into the dquot, I think.
  * rpc's that look at user dquot's would then have to
  * push on the dependency recorded in the dquot
  */
-/* ARGSUSED */
 STATIC void
 xfs_qm_dquot_logitem_committing(
-       xfs_dq_logitem_t        *l,
+       struct xfs_log_item     *lip,
        xfs_lsn_t               lsn)
 {
-       return;
 }
 
-
 /*
  * This is the ops vector for dquots
  */
 static struct xfs_item_ops xfs_dquot_item_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_qm_dquot_logitem_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
-                                       xfs_qm_dquot_logitem_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))
-                                       xfs_qm_dquot_logitem_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_dquot_logitem_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
-       .iop_pushbuf    = (void(*)(xfs_log_item_t*))
-                                       xfs_qm_dquot_logitem_pushbuf,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_dquot_logitem_committing
+       .iop_size       = xfs_qm_dquot_logitem_size,
+       .iop_format     = xfs_qm_dquot_logitem_format,
+       .iop_pin        = xfs_qm_dquot_logitem_pin,
+       .iop_unpin      = xfs_qm_dquot_logitem_unpin,
+       .iop_trylock    = xfs_qm_dquot_logitem_trylock,
+       .iop_unlock     = xfs_qm_dquot_logitem_unlock,
+       .iop_committed  = xfs_qm_dquot_logitem_committed,
+       .iop_push       = xfs_qm_dquot_logitem_push,
+       .iop_pushbuf    = xfs_qm_dquot_logitem_pushbuf,
+       .iop_committing = xfs_qm_dquot_logitem_committing
 };
 
 /*
@@ -350,10 +312,9 @@ static struct xfs_item_ops xfs_dquot_item_ops = {
  */
 void
 xfs_qm_dquot_logitem_init(
-       struct xfs_dquot *dqp)
+       struct xfs_dquot        *dqp)
 {
-       xfs_dq_logitem_t  *lp;
-       lp = &dqp->q_logitem;
+       struct xfs_dq_logitem   *lp = &dqp->q_logitem;
 
        xfs_log_item_init(dqp->q_mount, &lp->qli_item, XFS_LI_DQUOT,
                                        &xfs_dquot_item_ops);
@@ -374,16 +335,22 @@ xfs_qm_dquot_logitem_init(
 
 /*------------------  QUOTAOFF LOG ITEMS  -------------------*/
 
+static inline struct xfs_qoff_logitem *QOFF_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_qoff_logitem, qql_item);
+}
+
+
 /*
  * This returns the number of iovecs needed to log the given quotaoff item.
  * We only need 1 iovec for an quotaoff item.  It just logs the
  * quotaoff_log_format structure.
  */
-/*ARGSUSED*/
 STATIC uint
-xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_size(
+       struct xfs_log_item     *lip)
 {
-       return (1);
+       return 1;
 }
 
 /*
@@ -394,53 +361,46 @@ xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
  * slots in the quotaoff item have been filled.
  */
 STATIC void
-xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t  *qf,
-                          xfs_log_iovec_t      *log_vector)
+xfs_qm_qoff_logitem_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *log_vector)
 {
-       ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
+       struct xfs_qoff_logitem *qflip = QOFF_ITEM(lip);
+
+       ASSERT(qflip->qql_format.qf_type == XFS_LI_QUOTAOFF);
 
-       log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
+       log_vector->i_addr = &qflip->qql_format;
        log_vector->i_len = sizeof(xfs_qoff_logitem_t);
        log_vector->i_type = XLOG_REG_TYPE_QUOTAOFF;
-       qf->qql_format.qf_size = 1;
+       qflip->qql_format.qf_size = 1;
 }
 
-
 /*
  * Pinning has no meaning for an quotaoff item, so just return.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_pin(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
-
 /*
  * Since pinning has no meaning for an quotaoff item, unpinning does
  * not either.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_unpin(
+       struct xfs_log_item     *lip,
+       int                     remove)
 {
-       return;
-}
-
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
-{
-       return;
 }
 
 /*
  * Quotaoff items have no locking, so just return success.
  */
-/*ARGSUSED*/
 STATIC uint
-xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_trylock(
+       struct xfs_log_item     *lip)
 {
        return XFS_ITEM_LOCKED;
 }
@@ -449,53 +409,51 @@ xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
  * Quotaoff items have no locking or pushing, so return failure
  * so that the caller doesn't bother with us.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_unlock(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
 /*
  * The quotaoff-start-item is logged only once and cannot be moved in the log,
  * so simply return the lsn at which it's been logged.
  */
-/*ARGSUSED*/
 STATIC xfs_lsn_t
-xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
+xfs_qm_qoff_logitem_committed(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
 {
-       return (lsn);
+       return lsn;
 }
 
 /*
  * There isn't much you can do to push on an quotaoff item.  It is simply
  * stuck waiting for the log to be flushed to disk.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_push(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
 
-/*ARGSUSED*/
 STATIC xfs_lsn_t
 xfs_qm_qoffend_logitem_committed(
-       xfs_qoff_logitem_t *qfe,
-       xfs_lsn_t lsn)
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
 {
-       xfs_qoff_logitem_t      *qfs;
-       struct xfs_ail          *ailp;
+       struct xfs_qoff_logitem *qfe = QOFF_ITEM(lip);
+       struct xfs_qoff_logitem *qfs = qfe->qql_start_lip;
+       struct xfs_ail          *ailp = qfs->qql_item.li_ailp;
 
-       qfs = qfe->qql_start_lip;
-       ailp = qfs->qql_item.li_ailp;
-       spin_lock(&ailp->xa_lock);
        /*
         * Delete the qoff-start logitem from the AIL.
         * xfs_trans_ail_delete() drops the AIL lock.
         */
+       spin_lock(&ailp->xa_lock);
        xfs_trans_ail_delete(ailp, (xfs_log_item_t *)qfs);
+
        kmem_free(qfs);
        kmem_free(qfe);
        return (xfs_lsn_t)-1;
@@ -515,71 +473,52 @@ xfs_qm_qoffend_logitem_committed(
  * (truly makes the quotaoff irrevocable).  If we do something else,
  * then maybe we don't need two.
  */
-/* ARGSUSED */
-STATIC void
-xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
-{
-       return;
-}
-
-/* ARGSUSED */
 STATIC void
-xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
+xfs_qm_qoff_logitem_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               commit_lsn)
 {
-       return;
 }
 
 static struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_qm_qoff_logitem_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
-                                       xfs_qm_qoff_logitem_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoffend_logitem_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
-       .iop_pushbuf    = NULL,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoffend_logitem_committing
+       .iop_size       = xfs_qm_qoff_logitem_size,
+       .iop_format     = xfs_qm_qoff_logitem_format,
+       .iop_pin        = xfs_qm_qoff_logitem_pin,
+       .iop_unpin      = xfs_qm_qoff_logitem_unpin,
+       .iop_trylock    = xfs_qm_qoff_logitem_trylock,
+       .iop_unlock     = xfs_qm_qoff_logitem_unlock,
+       .iop_committed  = xfs_qm_qoffend_logitem_committed,
+       .iop_push       = xfs_qm_qoff_logitem_push,
+       .iop_committing = xfs_qm_qoff_logitem_committing
 };
 
 /*
  * This is the ops vector shared by all quotaoff-start log items.
  */
 static struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_qm_qoff_logitem_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
-                                       xfs_qm_qoff_logitem_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoff_logitem_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
-       .iop_pushbuf    = NULL,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoff_logitem_committing
+       .iop_size       = xfs_qm_qoff_logitem_size,
+       .iop_format     = xfs_qm_qoff_logitem_format,
+       .iop_pin        = xfs_qm_qoff_logitem_pin,
+       .iop_unpin      = xfs_qm_qoff_logitem_unpin,
+       .iop_trylock    = xfs_qm_qoff_logitem_trylock,
+       .iop_unlock     = xfs_qm_qoff_logitem_unlock,
+       .iop_committed  = xfs_qm_qoff_logitem_committed,
+       .iop_push       = xfs_qm_qoff_logitem_push,
+       .iop_committing = xfs_qm_qoff_logitem_committing
 };
 
 /*
  * Allocate and initialize an quotaoff item of the correct quota type(s).
  */
-xfs_qoff_logitem_t *
+struct xfs_qoff_logitem *
 xfs_qm_qoff_logitem_init(
-       struct xfs_mount *mp,
-       xfs_qoff_logitem_t *start,
-       uint flags)
+       struct xfs_mount        *mp,
+       struct xfs_qoff_logitem *start,
+       uint                    flags)
 {
-       xfs_qoff_logitem_t      *qf;
+       struct xfs_qoff_logitem *qf;
 
-       qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
+       qf = kmem_zalloc(sizeof(struct xfs_qoff_logitem), KM_SLEEP);
 
        xfs_log_item_init(mp, &qf->qql_item, XFS_LI_QUOTAOFF, start ?
                        &xfs_qm_qoffend_logitem_ops : &xfs_qm_qoff_logitem_ops);
@@ -587,5 +526,5 @@ xfs_qm_qoff_logitem_init(
        qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
        qf->qql_format.qf_flags = flags;
        qf->qql_start_lip = start;
-       return (qf);
+       return qf;
 }
index 67c018392d62a8ecef3c93f35c2b942b0b52137d..9a92407109a19921b2a0914711be6ce70b1b1f12 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_bmap.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -1497,7 +1490,7 @@ xfs_qm_dqiterate(
                                  maxlblkcnt - lblkno,
                                  XFS_BMAPI_METADATA,
                                  NULL,
-                                 0, map, &nmaps, NULL, NULL);
+                                 0, map, &nmaps, NULL);
                xfs_iunlock(qip, XFS_ILOCK_SHARED);
                if (error)
                        break;
@@ -1669,7 +1662,8 @@ xfs_qm_dqusage_adjust(
         * making us disable quotas for the file system.
         */
        if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
-               xfs_iput(ip, XFS_ILOCK_EXCL);
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               IRELE(ip);
                *res = BULKSTAT_RV_GIVEUP;
                return error;
        }
@@ -1682,7 +1676,8 @@ xfs_qm_dqusage_adjust(
                 * Walk thru the extent list and count the realtime blocks.
                 */
                if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
-                       xfs_iput(ip, XFS_ILOCK_EXCL);
+                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+                       IRELE(ip);
                        if (udqp)
                                xfs_qm_dqput(udqp);
                        if (gdqp)
index 97b410c12794d5ddf52579625d4a256ed384d872..bea02d786c5d30763e3ceee6022fe248a63fb454 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
-#include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_qm.h"
index 3d1fc79532e2ab3a2c736c5e799bdd3b39da71dc..8671a0b32644010a04e98f64518c63050add8048 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_bmap.h"
-#include "xfs_btree.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_qm.h"
index b4487764e923b7c493aac813e9161764a0f0ccfb..d257eb8557c43a873644ea6481ec5611b9a0051f 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_bmap.h"
-#include "xfs_btree.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
@@ -248,40 +238,74 @@ out_unlock:
        return error;
 }
 
+STATIC int
+xfs_qm_scall_trunc_qfile(
+       struct xfs_mount        *mp,
+       xfs_ino_t               ino)
+{
+       struct xfs_inode        *ip;
+       struct xfs_trans        *tp;
+       int                     error;
+
+       if (ino == NULLFSINO)
+               return 0;
+
+       error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
+       if (error)
+               return error;
+
+       xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
+       error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
+                                 XFS_TRANS_PERM_LOG_RES,
+                                 XFS_ITRUNCATE_LOG_COUNT);
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+               goto out_put;
+       }
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip);
+
+       error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, 1);
+       if (error) {
+               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+                                    XFS_TRANS_ABORT);
+               goto out_unlock;
+       }
+
+       xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+
+out_unlock:
+       xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+out_put:
+       IRELE(ip);
+       return error;
+}
+
 int
 xfs_qm_scall_trunc_qfiles(
        xfs_mount_t     *mp,
        uint            flags)
 {
        int             error = 0, error2 = 0;
-       xfs_inode_t     *qip;
 
        if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) {
                qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
                return XFS_ERROR(EINVAL);
        }
 
-       if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
-               error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip);
-               if (!error) {
-                       error = xfs_truncate_file(mp, qip);
-                       IRELE(qip);
-               }
-       }
-
-       if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) &&
-           mp->m_sb.sb_gquotino != NULLFSINO) {
-               error2 = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip);
-               if (!error2) {
-                       error2 = xfs_truncate_file(mp, qip);
-                       IRELE(qip);
-               }
-       }
+       if (flags & XFS_DQ_USER)
+               error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
+       if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
+               error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
 
        return error ? error : error2;
 }
 
-
 /*
  * Switch on (a given) quota enforcement for a filesystem.  This takes
  * effect immediately.
@@ -875,8 +899,9 @@ xfs_dqrele_inode(
                xfs_qm_dqrele(ip->i_gdquot);
                ip->i_gdquot = NULL;
        }
-       xfs_iput(ip, XFS_ILOCK_EXCL);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
+       IRELE(ip);
        return 0;
 }
 
@@ -1143,7 +1168,8 @@ xfs_qm_internalqcheck_adjust(
         * of those now.
         */
        if (! ipreleased) {
-               xfs_iput(ip, lock_flags);
+               xfs_iunlock(ip, lock_flags);
+               IRELE(ip);
                ipreleased = B_TRUE;
                goto again;
        }
@@ -1160,7 +1186,8 @@ xfs_qm_internalqcheck_adjust(
                ASSERT(gd);
                xfs_qm_internalqcheck_dqadjust(ip, gd);
        }
-       xfs_iput(ip, lock_flags);
+       xfs_iunlock(ip, lock_flags);
+       IRELE(ip);
        *res = BULKSTAT_RV_DIDONE;
        return (0);
 }
index 061d827da33cd6ea9411c99665ab74d309ebfde9..7de91d1b75c06c91daea768da891ab49a4152818 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
-#include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
@@ -59,16 +49,14 @@ xfs_trans_dqjoin(
        xfs_trans_t     *tp,
        xfs_dquot_t     *dqp)
 {
-       xfs_dq_logitem_t    *lp = &dqp->q_logitem;
-
        ASSERT(dqp->q_transp != tp);
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       ASSERT(lp->qli_dquot == dqp);
+       ASSERT(dqp->q_logitem.qli_dquot == dqp);
 
        /*
         * Get a log_item_desc to point at the new item.
         */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
+       xfs_trans_add_item(tp, &dqp->q_logitem.qli_item);
 
        /*
         * Initialize i_transp so we can later determine if this dquot is
@@ -93,16 +81,11 @@ xfs_trans_log_dquot(
        xfs_trans_t     *tp,
        xfs_dquot_t     *dqp)
 {
-       xfs_log_item_desc_t     *lidp;
-
        ASSERT(dqp->q_transp == tp);
        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
-       ASSERT(lidp != NULL);
-
        tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       dqp->q_logitem.qli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 }
 
 /*
@@ -874,9 +857,8 @@ xfs_trans_get_qoff_item(
        /*
         * Get a log_item_desc to point at the new item.
         */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
-
-       return (q);
+       xfs_trans_add_item(tp, &q->qql_item);
+       return q;
 }
 
 
@@ -890,13 +872,8 @@ xfs_trans_log_quotaoff_item(
        xfs_trans_t             *tp,
        xfs_qoff_logitem_t      *qlp)
 {
-       xfs_log_item_desc_t     *lidp;
-
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
-       ASSERT(lidp != NULL);
-
        tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       qlp->qql_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 }
 
 STATIC void
index 3f3610a7ee059210eea3beadbffe13f87609dce9..975aa10e1a47a3536499b035947ed0c5ac5098a5 100644 (file)
@@ -22,7 +22,6 @@
 #include "xfs_sb.h"
 #include "xfs_inum.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_error.h"
 
index a7fbe8a99b12bf2c360ea19372a380ae5d27c855..af168faccc7a5cb8edfacf2e0e0a350028d449fe 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
@@ -688,8 +683,6 @@ xfs_alloc_ag_vextent_near(
        xfs_agblock_t   ltbno;          /* start bno of left side entry */
        xfs_agblock_t   ltbnoa;         /* aligned ... */
        xfs_extlen_t    ltdiff;         /* difference to left side entry */
-       /*REFERENCED*/
-       xfs_agblock_t   ltend;          /* end bno of left side entry */
        xfs_extlen_t    ltlen;          /* length of left side entry */
        xfs_extlen_t    ltlena;         /* aligned ... */
        xfs_agblock_t   ltnew;          /* useful start bno of left side */
@@ -814,8 +807,7 @@ 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);
-               ltend = ltbno + ltlen;
-               ASSERT(ltend <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
+               ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
                args->len = blen;
                if (!xfs_alloc_fix_minleft(args)) {
                        xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
@@ -828,7 +820,7 @@ xfs_alloc_ag_vextent_near(
                 */
                args->agbno = bnew;
                ASSERT(bnew >= ltbno);
-               ASSERT(bnew + blen <= ltend);
+               ASSERT(bnew + blen <= ltbno + ltlen);
                /*
                 * Set up a cursor for the by-bno tree.
                 */
@@ -1157,7 +1149,6 @@ xfs_alloc_ag_vextent_near(
        /*
         * Fix up the length and compute the useful address.
         */
-       ltend = ltbno + ltlen;
        args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
        xfs_alloc_fix_len(args);
        if (!xfs_alloc_fix_minleft(args)) {
@@ -1170,7 +1161,7 @@ xfs_alloc_ag_vextent_near(
        (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, ltbno,
                ltlen, &ltnew);
        ASSERT(ltnew >= ltbno);
-       ASSERT(ltnew + rlen <= ltend);
+       ASSERT(ltnew + rlen <= ltbno + ltlen);
        ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
        args->agbno = ltnew;
        if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen,
index 6d05199b667cea3c72576750924a8ee8a63effcc..895009a97271fbbd27fcb63b97b9546f375a8778 100644 (file)
@@ -27,16 +27,16 @@ struct xfs_busy_extent;
 /*
  * Freespace allocation types.  Argument to xfs_alloc_[v]extent.
  */
-typedef enum xfs_alloctype
-{
-       XFS_ALLOCTYPE_ANY_AG,           /* allocate anywhere, use rotor */
-       XFS_ALLOCTYPE_FIRST_AG,         /* ... start at ag 0 */
-       XFS_ALLOCTYPE_START_AG,         /* anywhere, start in this a.g. */
-       XFS_ALLOCTYPE_THIS_AG,          /* anywhere in this a.g. */
-       XFS_ALLOCTYPE_START_BNO,        /* near this block else anywhere */
-       XFS_ALLOCTYPE_NEAR_BNO,         /* in this a.g. and near this block */
-       XFS_ALLOCTYPE_THIS_BNO          /* at exactly this block */
-} xfs_alloctype_t;
+#define XFS_ALLOCTYPE_ANY_AG   0x01    /* allocate anywhere, use rotor */
+#define XFS_ALLOCTYPE_FIRST_AG 0x02    /* ... start at ag 0 */
+#define XFS_ALLOCTYPE_START_AG 0x04    /* anywhere, start in this a.g. */
+#define XFS_ALLOCTYPE_THIS_AG  0x08    /* anywhere in this a.g. */
+#define XFS_ALLOCTYPE_START_BNO        0x10    /* near this block else anywhere */
+#define XFS_ALLOCTYPE_NEAR_BNO 0x20    /* in this a.g. and near this block */
+#define XFS_ALLOCTYPE_THIS_BNO 0x40    /* at exactly this block */
+
+/* this should become an enum again when the tracing code is fixed */
+typedef unsigned int xfs_alloctype_t;
 
 #define XFS_ALLOC_TYPES \
        { XFS_ALLOCTYPE_ANY_AG,         "ANY_AG" }, \
index 83f4942187594ac4b998712dc66b2385b083963e..97f7328967fdfe8148b8e1e2479feaa98499859b 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_btree_trace.h"
-#include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
index b9c196a53c42e219a6cca9113d95be704ecc8f9e..c2568242a9015eaf0bd571104bfc2c468fc2e6bb 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_alloc.h"
-#include "xfs_btree.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
@@ -325,8 +319,7 @@ xfs_attr_set_int(
                return (error);
        }
 
-       xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(args.trans, dp);
+       xfs_trans_ijoin(args.trans, dp);
 
        /*
         * If the attribute list is non-existent or a shortform list,
@@ -396,10 +389,8 @@ xfs_attr_set_int(
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args.trans, dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args.trans, dp);
 
                /*
                 * Commit the leaf transformation.  We'll need another (linked)
@@ -544,8 +535,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
         * No need to make quota reservations here. We expect to release some
         * blocks not allocate in the common case.
         */
-       xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(args.trans, dp);
+       xfs_trans_ijoin(args.trans, dp);
 
        /*
         * Decide on what work routines to call based on the inode size.
@@ -821,8 +811,7 @@ xfs_attr_inactive(xfs_inode_t *dp)
         * No need to make quota reservations here. We expect to release some
         * blocks, not allocate, in the common case.
         */
-       xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(trans, dp);
+       xfs_trans_ijoin(trans, dp);
 
        /*
         * Decide on what work routines to call based on the inode size.
@@ -981,10 +970,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args->trans, dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args->trans, dp);
 
                /*
                 * Commit the current trans (including the inode) and start
@@ -1085,10 +1072,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                         * and started a new one.  We need the inode to be
                         * in all transactions.
                         */
-                       if (committed) {
-                               xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                               xfs_trans_ihold(args->trans, dp);
-                       }
+                       if (committed)
+                               xfs_trans_ijoin(args->trans, dp);
                } else
                        xfs_da_buf_done(bp);
 
@@ -1161,10 +1146,8 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args->trans, dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args->trans, dp);
        } else
                xfs_da_buf_done(bp);
        return(0);
@@ -1317,10 +1300,8 @@ restart:
                         * and started a new one.  We need the inode to be
                         * in all transactions.
                         */
-                       if (committed) {
-                               xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                               xfs_trans_ihold(args->trans, dp);
-                       }
+                       if (committed)
+                               xfs_trans_ijoin(args->trans, dp);
 
                        /*
                         * Commit the node conversion and start the next
@@ -1356,10 +1337,8 @@ restart:
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args->trans, dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args->trans, dp);
        } else {
                /*
                 * Addition succeeded, update Btree hashvals.
@@ -1470,10 +1449,8 @@ restart:
                         * and started a new one.  We need the inode to be
                         * in all transactions.
                         */
-                       if (committed) {
-                               xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                               xfs_trans_ihold(args->trans, dp);
-                       }
+                       if (committed)
+                               xfs_trans_ijoin(args->trans, dp);
                }
 
                /*
@@ -1604,10 +1581,8 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args->trans, dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args->trans, dp);
 
                /*
                 * Commit the Btree join operation and start a new trans.
@@ -1658,10 +1633,8 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                         * and started a new one.  We need the inode to be
                         * in all transactions.
                         */
-                       if (committed) {
-                               xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                               xfs_trans_ihold(args->trans, dp);
-                       }
+                       if (committed)
+                               xfs_trans_ijoin(args->trans, dp);
                } else
                        xfs_da_brelse(args->trans, bp);
        }
@@ -2004,7 +1977,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
                error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
                                  args->rmtblkcnt,
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 NULL, 0, map, &nmap, NULL, NULL);
+                                 NULL, 0, map, &nmap, NULL);
                if (error)
                        return(error);
                ASSERT(nmap >= 1);
@@ -2083,7 +2056,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
                                                        XFS_BMAPI_WRITE,
                                  args->firstblock, args->total, &map, &nmap,
-                                 args->flist, NULL);
+                                 args->flist);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                &committed);
@@ -2099,10 +2072,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args->trans, dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args->trans, dp);
 
                ASSERT(nmap == 1);
                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
@@ -2136,7 +2107,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                                  args->rmtblkcnt,
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
                                  args->firstblock, 0, &map, &nmap,
-                                 NULL, NULL);
+                                 NULL);
                if (error) {
                        return(error);
                }
@@ -2201,7 +2172,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                                        args->rmtblkcnt,
                                        XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
                                        args->firstblock, 0, &map, &nmap,
-                                       args->flist, NULL);
+                                       args->flist);
                if (error) {
                        return(error);
                }
@@ -2239,7 +2210,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
                                    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
                                    1, args->firstblock, args->flist,
-                                   NULL, &done);
+                                   &done);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                &committed);
@@ -2255,10 +2226,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                 * bmap_finish() may have committed the last trans and started
                 * a new one.  We need the inode to be in all transactions.
                 */
-               if (committed) {
-                       xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(args->trans, args->dp);
-               }
+               if (committed)
+                       xfs_trans_ijoin(args->trans, args->dp);
 
                /*
                 * Close out trans and start the next one in the chain.
index a90ce74fc256904837381f61e49c0e569818e89f..a6cff8edcdb6a33cfa6b5554c06be24439801528 100644 (file)
@@ -24,8 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
@@ -33,7 +31,6 @@
 #include "xfs_ialloc_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_btree.h"
-#include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -2931,7 +2928,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
                nmap = 1;
                error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt,
                                        XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                       NULL, 0, &map, &nmap, NULL, NULL);
+                                       NULL, 0, &map, &nmap, NULL);
                if (error) {
                        return(error);
                }
index 99587ded043f84b580f0d3331df408a0aa0960fe..23f14e595c18cd3a8068796f5b73396fa9db98f9 100644 (file)
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_dir2_data.h"
 #include "xfs_dir2_leaf.h"
@@ -104,7 +101,6 @@ xfs_bmap_add_extent(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd);  /* OK to allocate reserved blocks */
 
@@ -122,7 +118,6 @@ xfs_bmap_add_extent_delay_real(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd);  /* OK to allocate reserved blocks */
 
 /*
@@ -135,7 +130,6 @@ xfs_bmap_add_extent_hole_delay(
        xfs_extnum_t            idx,    /* extent number to update/insert */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp,/* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd);  /* OK to allocate reserved blocks */
 
 /*
@@ -149,7 +143,6 @@ xfs_bmap_add_extent_hole_real(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork); /* data or attr fork */
 
 /*
@@ -162,8 +155,7 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_extnum_t            idx,    /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta); /* Change made to incore extents */
+       int                     *logflagsp); /* inode logging flags */
 
 /*
  * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
@@ -200,7 +192,6 @@ xfs_bmap_del_extent(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp,/* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd);   /* OK to allocate reserved blocks */
 
@@ -489,7 +480,6 @@ xfs_bmap_add_extent(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd)   /* OK to use reserved data blocks */
 {
@@ -524,15 +514,6 @@ xfs_bmap_add_extent(
                        logflags = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
                } else
                        logflags = 0;
-               /* DELTA: single new extent */
-               if (delta) {
-                       if (delta->xed_startoff > new->br_startoff)
-                               delta->xed_startoff = new->br_startoff;
-                       if (delta->xed_blockcount <
-                                       new->br_startoff + new->br_blockcount)
-                               delta->xed_blockcount = new->br_startoff +
-                                               new->br_blockcount;
-               }
        }
        /*
         * Any kind of new delayed allocation goes here.
@@ -542,7 +523,7 @@ xfs_bmap_add_extent(
                        ASSERT((cur->bc_private.b.flags &
                                XFS_BTCUR_BPRV_WASDEL) == 0);
                if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
-                               &logflags, delta, rsvd)))
+                               &logflags, rsvd)))
                        goto done;
        }
        /*
@@ -553,7 +534,7 @@ xfs_bmap_add_extent(
                        ASSERT((cur->bc_private.b.flags &
                                XFS_BTCUR_BPRV_WASDEL) == 0);
                if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
-                               &logflags, delta, whichfork)))
+                               &logflags, whichfork)))
                        goto done;
        } else {
                xfs_bmbt_irec_t prev;   /* old extent at offset idx */
@@ -578,17 +559,17 @@ xfs_bmap_add_extent(
                                                XFS_BTCUR_BPRV_WASDEL);
                                if ((error = xfs_bmap_add_extent_delay_real(ip,
                                        idx, &cur, new, &da_new, first, flist,
-                                       &logflags, delta, rsvd)))
+                                       &logflags, rsvd)))
                                        goto done;
                        } else if (new->br_state == XFS_EXT_NORM) {
                                ASSERT(new->br_state == XFS_EXT_NORM);
                                if ((error = xfs_bmap_add_extent_unwritten_real(
-                                       ip, idx, &cur, new, &logflags, delta)))
+                                       ip, idx, &cur, new, &logflags)))
                                        goto done;
                        } else {
                                ASSERT(new->br_state == XFS_EXT_UNWRITTEN);
                                if ((error = xfs_bmap_add_extent_unwritten_real(
-                                       ip, idx, &cur, new, &logflags, delta)))
+                                       ip, idx, &cur, new, &logflags)))
                                        goto done;
                        }
                        ASSERT(*curp == cur || *curp == NULL);
@@ -601,7 +582,7 @@ xfs_bmap_add_extent(
                                ASSERT((cur->bc_private.b.flags &
                                        XFS_BTCUR_BPRV_WASDEL) == 0);
                        if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
-                                       new, &logflags, delta, whichfork)))
+                                       new, &logflags, whichfork)))
                                goto done;
                }
        }
@@ -666,7 +647,6 @@ xfs_bmap_add_extent_delay_real(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd)   /* OK to use reserved data block allocation */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
@@ -797,11 +777,6 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                }
                *dnew = 0;
-               /* DELTA: Three in-core extents are replaced by one. */
-               temp = LEFT.br_startoff;
-               temp2 = LEFT.br_blockcount +
-                       PREV.br_blockcount +
-                       RIGHT.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -832,10 +807,6 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                }
                *dnew = 0;
-               /* DELTA: Two in-core extents are replaced by one. */
-               temp = LEFT.br_startoff;
-               temp2 = LEFT.br_blockcount +
-                       PREV.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -867,10 +838,6 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                }
                *dnew = 0;
-               /* DELTA: Two in-core extents are replaced by one. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount +
-                       RIGHT.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -900,9 +867,6 @@ xfs_bmap_add_extent_delay_real(
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
                *dnew = 0;
-               /* DELTA: The in-core extent described by new changed type. */
-               temp = new->br_startoff;
-               temp2 = new->br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -942,10 +906,6 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
                trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
                *dnew = temp;
-               /* DELTA: The boundary between two in-core extents moved. */
-               temp = LEFT.br_startoff;
-               temp2 = LEFT.br_blockcount +
-                       PREV.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING:
@@ -990,9 +950,6 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
                trace_xfs_bmap_post_update(ip, idx + 1, state, _THIS_IP_);
                *dnew = temp;
-               /* DELTA: One in-core extent is split in two. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount;
                break;
 
        case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1031,10 +988,6 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
                trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
                *dnew = temp;
-               /* DELTA: The boundary between two in-core extents moved. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount +
-                       RIGHT.br_blockcount;
                break;
 
        case BMAP_RIGHT_FILLING:
@@ -1078,9 +1031,6 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
                trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
                *dnew = temp;
-               /* DELTA: One in-core extent is split in two. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount;
                break;
 
        case 0:
@@ -1161,9 +1111,6 @@ xfs_bmap_add_extent_delay_real(
                        nullstartblock((int)temp2));
                trace_xfs_bmap_post_update(ip, idx + 2, state, _THIS_IP_);
                *dnew = temp + temp2;
-               /* DELTA: One in-core extent is split in three. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
@@ -1179,13 +1126,6 @@ xfs_bmap_add_extent_delay_real(
                ASSERT(0);
        }
        *curp = cur;
-       if (delta) {
-               temp2 += temp;
-               if (delta->xed_startoff > temp)
-                       delta->xed_startoff = temp;
-               if (delta->xed_blockcount < temp2)
-                       delta->xed_blockcount = temp2;
-       }
 done:
        *logflagsp = rval;
        return error;
@@ -1204,8 +1144,7 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_extnum_t            idx,    /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta) /* Change made to incore extents */
+       int                     *logflagsp) /* inode logging flags */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
        xfs_bmbt_rec_host_t     *ep;    /* extent entry for idx */
@@ -1219,8 +1158,6 @@ xfs_bmap_add_extent_unwritten_real(
                                        /* left is 0, right is 1, prev is 2 */
        int                     rval=0; /* return value (logging flags) */
        int                     state = 0;/* state bits, accessed thru macros */
-       xfs_filblks_t           temp=0;
-       xfs_filblks_t           temp2=0;
 
 #define        LEFT            r[0]
 #define        RIGHT           r[1]
@@ -1341,11 +1278,6 @@ xfs_bmap_add_extent_unwritten_real(
                                RIGHT.br_blockcount, LEFT.br_state)))
                                goto done;
                }
-               /* DELTA: Three in-core extents are replaced by one. */
-               temp = LEFT.br_startoff;
-               temp2 = LEFT.br_blockcount +
-                       PREV.br_blockcount +
-                       RIGHT.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -1382,10 +1314,6 @@ xfs_bmap_add_extent_unwritten_real(
                                LEFT.br_state)))
                                goto done;
                }
-               /* DELTA: Two in-core extents are replaced by one. */
-               temp = LEFT.br_startoff;
-               temp2 = LEFT.br_blockcount +
-                       PREV.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1422,10 +1350,6 @@ xfs_bmap_add_extent_unwritten_real(
                                newext)))
                                goto done;
                }
-               /* DELTA: Two in-core extents are replaced by one. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount +
-                       RIGHT.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -1453,9 +1377,6 @@ xfs_bmap_add_extent_unwritten_real(
                                newext)))
                                goto done;
                }
-               /* DELTA: The in-core extent described by new changed type. */
-               temp = new->br_startoff;
-               temp2 = new->br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -1501,10 +1422,6 @@ xfs_bmap_add_extent_unwritten_real(
                                LEFT.br_state))
                                goto done;
                }
-               /* DELTA: The boundary between two in-core extents moved. */
-               temp = LEFT.br_startoff;
-               temp2 = LEFT.br_blockcount +
-                       PREV.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING:
@@ -1544,9 +1461,6 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               /* DELTA: One in-core extent is split in two. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount;
                break;
 
        case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1587,10 +1501,6 @@ xfs_bmap_add_extent_unwritten_real(
                                newext)))
                                goto done;
                }
-               /* DELTA: The boundary between two in-core extents moved. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount +
-                       RIGHT.br_blockcount;
                break;
 
        case BMAP_RIGHT_FILLING:
@@ -1630,9 +1540,6 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               /* DELTA: One in-core extent is split in two. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount;
                break;
 
        case 0:
@@ -1692,9 +1599,6 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               /* DELTA: One in-core extent is split in three. */
-               temp = PREV.br_startoff;
-               temp2 = PREV.br_blockcount;
                break;
 
        case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
@@ -1710,13 +1614,6 @@ xfs_bmap_add_extent_unwritten_real(
                ASSERT(0);
        }
        *curp = cur;
-       if (delta) {
-               temp2 += temp;
-               if (delta->xed_startoff > temp)
-                       delta->xed_startoff = temp;
-               if (delta->xed_blockcount < temp2)
-                       delta->xed_blockcount = temp2;
-       }
 done:
        *logflagsp = rval;
        return error;
@@ -1736,7 +1633,6 @@ xfs_bmap_add_extent_hole_delay(
        xfs_extnum_t            idx,    /* extent number to update/insert */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd)           /* OK to allocate reserved blocks */
 {
        xfs_bmbt_rec_host_t     *ep;    /* extent record for idx */
@@ -1747,7 +1643,6 @@ xfs_bmap_add_extent_hole_delay(
        xfs_bmbt_irec_t         right;  /* right neighbor extent entry */
        int                     state;  /* state bits, accessed thru macros */
        xfs_filblks_t           temp=0; /* temp for indirect calculations */
-       xfs_filblks_t           temp2=0;
 
        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
        ep = xfs_iext_get_ext(ifp, idx);
@@ -1819,9 +1714,6 @@ xfs_bmap_add_extent_hole_delay(
 
                xfs_iext_remove(ip, idx, 1, state);
                ip->i_df.if_lastex = idx - 1;
-               /* DELTA: Two in-core extents were replaced by one. */
-               temp2 = temp;
-               temp = left.br_startoff;
                break;
 
        case BMAP_LEFT_CONTIG:
@@ -1841,9 +1733,6 @@ xfs_bmap_add_extent_hole_delay(
                trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
 
                ip->i_df.if_lastex = idx - 1;
-               /* DELTA: One in-core extent grew into a hole. */
-               temp2 = temp;
-               temp = left.br_startoff;
                break;
 
        case BMAP_RIGHT_CONTIG:
@@ -1862,9 +1751,6 @@ xfs_bmap_add_extent_hole_delay(
                trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
 
                ip->i_df.if_lastex = idx;
-               /* DELTA: One in-core extent grew into a hole. */
-               temp2 = temp;
-               temp = new->br_startoff;
                break;
 
        case 0:
@@ -1876,9 +1762,6 @@ xfs_bmap_add_extent_hole_delay(
                oldlen = newlen = 0;
                xfs_iext_insert(ip, idx, 1, new, state);
                ip->i_df.if_lastex = idx;
-               /* DELTA: A new in-core extent was added in a hole. */
-               temp2 = new->br_blockcount;
-               temp = new->br_startoff;
                break;
        }
        if (oldlen != newlen) {
@@ -1889,13 +1772,6 @@ xfs_bmap_add_extent_hole_delay(
                 * Nothing to do for disk quota accounting here.
                 */
        }
-       if (delta) {
-               temp2 += temp;
-               if (delta->xed_startoff > temp)
-                       delta->xed_startoff = temp;
-               if (delta->xed_blockcount < temp2)
-                       delta->xed_blockcount = temp2;
-       }
        *logflagsp = 0;
        return 0;
 }
@@ -1911,7 +1787,6 @@ xfs_bmap_add_extent_hole_real(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork) /* data or attr fork */
 {
        xfs_bmbt_rec_host_t     *ep;    /* pointer to extent entry ins. point */
@@ -1922,8 +1797,6 @@ xfs_bmap_add_extent_hole_real(
        xfs_bmbt_irec_t         right;  /* right neighbor extent entry */
        int                     rval=0; /* return value (logging flags) */
        int                     state;  /* state bits, accessed thru macros */
-       xfs_filblks_t           temp=0;
-       xfs_filblks_t           temp2=0;
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
@@ -2020,11 +1893,6 @@ xfs_bmap_add_extent_hole_real(
                                        left.br_state)))
                                goto done;
                }
-               /* DELTA: Two in-core extents were replaced by one. */
-               temp = left.br_startoff;
-               temp2 = left.br_blockcount +
-                       new->br_blockcount +
-                       right.br_blockcount;
                break;
 
        case BMAP_LEFT_CONTIG:
@@ -2056,10 +1924,6 @@ xfs_bmap_add_extent_hole_real(
                                        left.br_state)))
                                goto done;
                }
-               /* DELTA: One in-core extent grew. */
-               temp = left.br_startoff;
-               temp2 = left.br_blockcount +
-                       new->br_blockcount;
                break;
 
        case BMAP_RIGHT_CONTIG:
@@ -2092,10 +1956,6 @@ xfs_bmap_add_extent_hole_real(
                                        right.br_state)))
                                goto done;
                }
-               /* DELTA: One in-core extent grew. */
-               temp = new->br_startoff;
-               temp2 = new->br_blockcount +
-                       right.br_blockcount;
                break;
 
        case 0:
@@ -2123,18 +1983,8 @@ xfs_bmap_add_extent_hole_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               /* DELTA: A new extent was added in a hole. */
-               temp = new->br_startoff;
-               temp2 = new->br_blockcount;
                break;
        }
-       if (delta) {
-               temp2 += temp;
-               if (delta->xed_startoff > temp)
-                       delta->xed_startoff = temp;
-               if (delta->xed_blockcount < temp2)
-                       delta->xed_blockcount = temp2;
-       }
 done:
        *logflagsp = rval;
        return error;
@@ -2959,7 +2809,6 @@ xfs_bmap_del_extent(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *del,   /* data to remove from extents */
        int                     *logflagsp, /* inode logging flags */
-       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd)   /* OK to allocate reserved blocks */
 {
@@ -3265,14 +3114,6 @@ xfs_bmap_del_extent(
        if (da_old > da_new)
                xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int64_t)(da_old - da_new),
                        rsvd);
-       if (delta) {
-               /* DELTA: report the original extent. */
-               if (delta->xed_startoff > got.br_startoff)
-                       delta->xed_startoff = got.br_startoff;
-               if (delta->xed_blockcount < got.br_startoff+got.br_blockcount)
-                       delta->xed_blockcount = got.br_startoff +
-                                                       got.br_blockcount;
-       }
 done:
        *logflagsp = flags;
        return error;
@@ -3754,9 +3595,10 @@ xfs_bmap_add_attrfork(
                ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
        }
        ASSERT(ip->i_d.di_anextents == 0);
-       IHOLD(ip);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
        switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_DEV:
                ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
@@ -4483,8 +4325,7 @@ xfs_bmapi(
        xfs_extlen_t    total,          /* total blocks needed */
        xfs_bmbt_irec_t *mval,          /* output: map values */
        int             *nmap,          /* i/o: mval size/count */
-       xfs_bmap_free_t *flist,         /* i/o: list extents to free */
-       xfs_extdelta_t  *delta)         /* o: change made to incore extents */
+       xfs_bmap_free_t *flist)         /* i/o: list extents to free */
 {
        xfs_fsblock_t   abno;           /* allocated block number */
        xfs_extlen_t    alen;           /* allocated extent length */
@@ -4596,10 +4437,7 @@ xfs_bmapi(
        end = bno + len;
        obno = bno;
        bma.ip = NULL;
-       if (delta) {
-               delta->xed_startoff = NULLFILEOFF;
-               delta->xed_blockcount = 0;
-       }
+
        while (bno < end && n < *nmap) {
                /*
                 * Reading past eof, act as though there's a hole
@@ -4620,19 +4458,13 @@ xfs_bmapi(
                         * allocate the stuff asked for in this bmap call
                         * but that wouldn't be as good.
                         */
-                       if (wasdelay && !(flags & XFS_BMAPI_EXACT)) {
+                       if (wasdelay) {
                                alen = (xfs_extlen_t)got.br_blockcount;
                                aoff = got.br_startoff;
                                if (lastx != NULLEXTNUM && lastx) {
                                        ep = xfs_iext_get_ext(ifp, lastx - 1);
                                        xfs_bmbt_get_all(ep, &prev);
                                }
-                       } else if (wasdelay) {
-                               alen = (xfs_extlen_t)
-                                       XFS_FILBLKS_MIN(len,
-                                               (got.br_startoff +
-                                                got.br_blockcount) - bno);
-                               aoff = bno;
                        } else {
                                alen = (xfs_extlen_t)
                                        XFS_FILBLKS_MIN(len, MAXEXTLEN);
@@ -4831,7 +4663,7 @@ xfs_bmapi(
                                        got.br_state = XFS_EXT_UNWRITTEN;
                        }
                        error = xfs_bmap_add_extent(ip, lastx, &cur, &got,
-                               firstblock, flist, &tmp_logflags, delta,
+                               firstblock, flist, &tmp_logflags,
                                whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
                        logflags |= tmp_logflags;
                        if (error)
@@ -4927,7 +4759,7 @@ xfs_bmapi(
                        }
                        mval->br_state = XFS_EXT_NORM;
                        error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
-                               firstblock, flist, &tmp_logflags, delta,
+                               firstblock, flist, &tmp_logflags,
                                whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
                        logflags |= tmp_logflags;
                        if (error)
@@ -5017,14 +4849,6 @@ xfs_bmapi(
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE ||
               XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max);
        error = 0;
-       if (delta && delta->xed_startoff != NULLFILEOFF) {
-               /* A change was actually made.
-                * Note that delta->xed_blockount is an offset at this
-                * point and needs to be converted to a block count.
-                */
-               ASSERT(delta->xed_blockcount > delta->xed_startoff);
-               delta->xed_blockcount -= delta->xed_startoff;
-       }
 error0:
        /*
         * Log everything.  Do this after conversion, there's no point in
@@ -5136,8 +4960,6 @@ xfs_bunmapi(
        xfs_fsblock_t           *firstblock,    /* first allocated block
                                                   controls a.g. for allocs */
        xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       xfs_extdelta_t          *delta,         /* o: change made to incore
-                                                  extents */
        int                     *done)          /* set if not done yet */
 {
        xfs_btree_cur_t         *cur;           /* bmap btree cursor */
@@ -5196,10 +5018,7 @@ xfs_bunmapi(
        bno = start + len - 1;
        ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
                &prev);
-       if (delta) {
-               delta->xed_startoff = NULLFILEOFF;
-               delta->xed_blockcount = 0;
-       }
+
        /*
         * Check to see if the given block number is past the end of the
         * file, back up to the last block if so...
@@ -5297,7 +5116,7 @@ xfs_bunmapi(
                        }
                        del.br_state = XFS_EXT_UNWRITTEN;
                        error = xfs_bmap_add_extent(ip, lastx, &cur, &del,
-                               firstblock, flist, &logflags, delta,
+                               firstblock, flist, &logflags,
                                XFS_DATA_FORK, 0);
                        if (error)
                                goto error0;
@@ -5352,7 +5171,7 @@ xfs_bunmapi(
                                prev.br_state = XFS_EXT_UNWRITTEN;
                                error = xfs_bmap_add_extent(ip, lastx - 1, &cur,
                                        &prev, firstblock, flist, &logflags,
-                                       delta, XFS_DATA_FORK, 0);
+                                       XFS_DATA_FORK, 0);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5361,7 +5180,7 @@ xfs_bunmapi(
                                del.br_state = XFS_EXT_UNWRITTEN;
                                error = xfs_bmap_add_extent(ip, lastx, &cur,
                                        &del, firstblock, flist, &logflags,
-                                       delta, XFS_DATA_FORK, 0);
+                                       XFS_DATA_FORK, 0);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5414,7 +5233,7 @@ xfs_bunmapi(
                        goto error0;
                }
                error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del,
-                               &tmp_logflags, delta, whichfork, rsvd);
+                               &tmp_logflags, whichfork, rsvd);
                logflags |= tmp_logflags;
                if (error)
                        goto error0;
@@ -5471,14 +5290,6 @@ nodelete:
        ASSERT(ifp->if_ext_max ==
               XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
        error = 0;
-       if (delta && delta->xed_startoff != NULLFILEOFF) {
-               /* A change was actually made.
-                * Note that delta->xed_blockount is an offset at this
-                * point and needs to be converted to a block count.
-                */
-               ASSERT(delta->xed_blockcount > delta->xed_startoff);
-               delta->xed_blockcount -= delta->xed_startoff;
-       }
 error0:
        /*
         * Log everything.  Do this after conversion, there's no point in
@@ -5605,28 +5416,6 @@ xfs_getbmap(
                prealloced = 0;
                fixlen = 1LL << 32;
        } else {
-               /*
-                * If the BMV_IF_NO_DMAPI_READ interface bit specified, do
-                * not generate a DMAPI read event.  Otherwise, if the
-                * DM_EVENT_READ bit is set for the file, generate a read
-                * event in order that the DMAPI application may do its thing
-                * before we return the extents.  Usually this means restoring
-                * user file data to regions of the file that look like holes.
-                *
-                * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify
-                * BMV_IF_NO_DMAPI_READ so that read events are generated.
-                * If this were not true, callers of ioctl(XFS_IOC_GETBMAP)
-                * could misinterpret holes in a DMAPI file as true holes,
-                * when in fact they may represent offline user data.
-                */
-               if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) &&
-                   !(iflags & BMV_IF_NO_DMAPI_READ)) {
-                       error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip,
-                                             0, 0, 0, NULL);
-                       if (error)
-                               return XFS_ERROR(error);
-               }
-
                if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
                    ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
                    ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
@@ -5713,7 +5502,7 @@ xfs_getbmap(
                error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
                                  XFS_BB_TO_FSB(mp, bmv->bmv_length),
                                  bmapi_flags, NULL, 0, map, &nmap,
-                                 NULL, NULL);
+                                 NULL);
                if (error)
                        goto out_free_map;
                ASSERT(nmap <= subnex);
@@ -5859,66 +5648,34 @@ xfs_bmap_eof(
 }
 
 #ifdef DEBUG
-STATIC
-xfs_buf_t *
+STATIC struct xfs_buf *
 xfs_bmap_get_bp(
-       xfs_btree_cur_t         *cur,
+       struct xfs_btree_cur    *cur,
        xfs_fsblock_t           bno)
 {
-       int i;
-       xfs_buf_t *bp;
+       struct xfs_log_item_desc *lidp;
+       int                     i;
 
        if (!cur)
-               return(NULL);
-
-       bp = NULL;
-       for(i = 0; i < XFS_BTREE_MAXLEVELS; i++) {
-               bp = cur->bc_bufs[i];
-               if (!bp) break;
-               if (XFS_BUF_ADDR(bp) == bno)
-                       break;  /* Found it */
-       }
-       if (i == XFS_BTREE_MAXLEVELS)
-               bp = NULL;
-
-       if (!bp) { /* Chase down all the log items to see if the bp is there */
-               xfs_log_item_chunk_t    *licp;
-               xfs_trans_t             *tp;
-
-               tp = cur->bc_tp;
-               licp = &tp->t_items;
-               while (!bp && licp != NULL) {
-                       if (xfs_lic_are_all_free(licp)) {
-                               licp = licp->lic_next;
-                               continue;
-                       }
-                       for (i = 0; i < licp->lic_unused; i++) {
-                               xfs_log_item_desc_t     *lidp;
-                               xfs_log_item_t          *lip;
-                               xfs_buf_log_item_t      *bip;
-                               xfs_buf_t               *lbp;
-
-                               if (xfs_lic_isfree(licp, i)) {
-                                       continue;
-                               }
-
-                               lidp = xfs_lic_slot(licp, i);
-                               lip = lidp->lid_item;
-                               if (lip->li_type != XFS_LI_BUF)
-                                       continue;
+               return NULL;
 
-                               bip = (xfs_buf_log_item_t *)lip;
-                               lbp = bip->bli_buf;
+       for (i = 0; i < XFS_BTREE_MAXLEVELS; i++) {
+               if (!cur->bc_bufs[i])
+                       break;
+               if (XFS_BUF_ADDR(cur->bc_bufs[i]) == bno)
+                       return cur->bc_bufs[i];
+       }
 
-                               if (XFS_BUF_ADDR(lbp) == bno) {
-                                       bp = lbp;
-                                       break; /* Found it */
-                               }
-                       }
-                       licp = licp->lic_next;
-               }
+       /* Chase down all the log items to see if the bp is there */
+       list_for_each_entry(lidp, &cur->bc_tp->t_items, lid_trans) {
+               struct xfs_buf_log_item *bip;
+               bip = (struct xfs_buf_log_item *)lidp->lid_item;
+               if (bip->bli_item.li_type == XFS_LI_BUF &&
+                   XFS_BUF_ADDR(bip->bli_buf) == bno)
+                       return bip->bli_buf;
        }
-       return(bp);
+
+       return NULL;
 }
 
 STATIC void
index 419dafb9d87d4a2a79b440c30a54e672a571b55f..b13569a6179b7235f315fe87f624e42336310c9e 100644 (file)
@@ -27,20 +27,6 @@ struct xfs_trans;
 
 extern kmem_zone_t     *xfs_bmap_free_item_zone;
 
-/*
- * DELTA: describe a change to the in-core extent list.
- *
- * Internally the use of xed_blockount is somewhat funky.
- * xed_blockcount contains an offset much of the time because this
- * makes merging changes easier.  (xfs_fileoff_t and xfs_filblks_t are
- * the same underlying type).
- */
-typedef struct xfs_extdelta
-{
-       xfs_fileoff_t           xed_startoff;   /* offset of range */
-       xfs_filblks_t           xed_blockcount; /* blocks in range */
-} xfs_extdelta_t;
-
 /*
  * List of extents to be free "later".
  * The list is kept sorted on xbf_startblock.
@@ -82,16 +68,13 @@ typedef     struct xfs_bmap_free
 #define XFS_BMAPI_DELAY                0x002   /* delayed write operation */
 #define XFS_BMAPI_ENTIRE       0x004   /* return entire extent, not trimmed */
 #define XFS_BMAPI_METADATA     0x008   /* mapping metadata not user data */
-#define XFS_BMAPI_EXACT                0x010   /* allocate only to spec'd bounds */
-#define XFS_BMAPI_ATTRFORK     0x020   /* use attribute fork not data */
-#define XFS_BMAPI_ASYNC                0x040   /* bunmapi xactions can be async */
-#define XFS_BMAPI_RSVBLOCKS    0x080   /* OK to alloc. reserved data blocks */
-#define        XFS_BMAPI_PREALLOC      0x100   /* preallocation op: unwritten space */
-#define        XFS_BMAPI_IGSTATE       0x200   /* Ignore state - */
+#define XFS_BMAPI_ATTRFORK     0x010   /* use attribute fork not data */
+#define XFS_BMAPI_RSVBLOCKS    0x020   /* OK to alloc. reserved data blocks */
+#define        XFS_BMAPI_PREALLOC      0x040   /* preallocation op: unwritten space */
+#define        XFS_BMAPI_IGSTATE       0x080   /* Ignore state - */
                                        /* combine contig. space */
-#define        XFS_BMAPI_CONTIG        0x400   /* must allocate only one extent */
-/*     XFS_BMAPI_DIRECT_IO     0x800   */
-#define XFS_BMAPI_CONVERT      0x1000  /* unwritten extent conversion - */
+#define        XFS_BMAPI_CONTIG        0x100   /* must allocate only one extent */
+#define XFS_BMAPI_CONVERT      0x200   /* unwritten extent conversion - */
                                        /* need write cache flushing and no */
                                        /* additional allocation alignments */
 
@@ -100,9 +83,7 @@ typedef      struct xfs_bmap_free
        { XFS_BMAPI_DELAY,      "DELAY" }, \
        { XFS_BMAPI_ENTIRE,     "ENTIRE" }, \
        { XFS_BMAPI_METADATA,   "METADATA" }, \
-       { XFS_BMAPI_EXACT,      "EXACT" }, \
        { XFS_BMAPI_ATTRFORK,   "ATTRFORK" }, \
-       { XFS_BMAPI_ASYNC,      "ASYNC" }, \
        { XFS_BMAPI_RSVBLOCKS,  "RSVBLOCKS" }, \
        { XFS_BMAPI_PREALLOC,   "PREALLOC" }, \
        { XFS_BMAPI_IGSTATE,    "IGSTATE" }, \
@@ -310,9 +291,7 @@ xfs_bmapi(
        xfs_extlen_t            total,          /* total blocks needed */
        struct xfs_bmbt_irec    *mval,          /* output: map values */
        int                     *nmap,          /* i/o: mval size/count */
-       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       xfs_extdelta_t          *delta);        /* o: change made to incore
-                                                  extents */
+       xfs_bmap_free_t         *flist);        /* i/o: list extents to free */
 
 /*
  * Map file blocks to filesystem blocks, simple version.
@@ -346,8 +325,6 @@ xfs_bunmapi(
        xfs_fsblock_t           *firstblock,    /* first allocated block
                                                   controls a.g. for allocs */
        xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       xfs_extdelta_t          *delta,         /* o: change made to incore
-                                                  extents */
        int                     *done);         /* set if not done yet */
 
 /*
index 416e47e54b83fc79f2472f59de81d8a34769e940..87d3c10b695437da9043d9a72985b8d8d25280c6 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_alloc.h"
 #include "xfs_btree.h"
 #include "xfs_btree_trace.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_bmap.h"
 #include "xfs_error.h"
index 96be4b0f249613fef3b0cc8ab0ae443dafc3d2f4..829af92f0fbadd0f4e311b8151055cc9e135e969 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_btree.h"
 #include "xfs_btree_trace.h"
-#include "xfs_ialloc.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
 
index 02a80984aa05f13189f4c99f186f1f098fa02e3d..1b09d7a280dfa6f1e1abcf247f27989da5fd6fc4 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
 
 kmem_zone_t    *xfs_buf_item_zone;
 
+static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_buf_log_item, bli_item);
+}
+
+
 #ifdef XFS_TRANS_DEBUG
 /*
  * This function uses an alternate strategy for tracking the bytes
@@ -151,12 +156,13 @@ STATIC void       xfs_buf_do_callbacks(xfs_buf_t *bp, xfs_log_item_t *lip);
  */
 STATIC uint
 xfs_buf_item_size(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip)
 {
-       uint            nvecs;
-       int             next_bit;
-       int             last_bit;
-       xfs_buf_t       *bp;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf          *bp = bip->bli_buf;
+       uint                    nvecs;
+       int                     next_bit;
+       int                     last_bit;
 
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        if (bip->bli_flags & XFS_BLI_STALE) {
@@ -170,7 +176,6 @@ xfs_buf_item_size(
                return 1;
        }
 
-       bp = bip->bli_buf;
        ASSERT(bip->bli_flags & XFS_BLI_LOGGED);
        nvecs = 1;
        last_bit = xfs_next_bit(bip->bli_format.blf_data_map,
@@ -219,13 +224,13 @@ xfs_buf_item_size(
  */
 STATIC void
 xfs_buf_item_format(
-       xfs_buf_log_item_t      *bip,
-       xfs_log_iovec_t         *log_vector)
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *vecp)
 {
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf  *bp = bip->bli_buf;
        uint            base_size;
        uint            nvecs;
-       xfs_log_iovec_t *vecp;
-       xfs_buf_t       *bp;
        int             first_bit;
        int             last_bit;
        int             next_bit;
@@ -235,8 +240,6 @@ xfs_buf_item_format(
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
               (bip->bli_flags & XFS_BLI_STALE));
-       bp = bip->bli_buf;
-       vecp = log_vector;
 
        /*
         * The size of the base structure is the size of the
@@ -248,7 +251,7 @@ xfs_buf_item_format(
        base_size =
                (uint)(sizeof(xfs_buf_log_format_t) +
                       ((bip->bli_format.blf_map_size - 1) * sizeof(uint)));
-       vecp->i_addr = (xfs_caddr_t)&bip->bli_format;
+       vecp->i_addr = &bip->bli_format;
        vecp->i_len = base_size;
        vecp->i_type = XLOG_REG_TYPE_BFORMAT;
        vecp++;
@@ -263,7 +266,7 @@ xfs_buf_item_format(
         */
        if (bip->bli_flags & XFS_BLI_INODE_BUF) {
                if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
-                     xfs_log_item_in_current_chkpt(&bip->bli_item)))
+                     xfs_log_item_in_current_chkpt(lip)))
                        bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF;
                bip->bli_flags &= ~XFS_BLI_INODE_BUF;
        }
@@ -356,66 +359,90 @@ xfs_buf_item_format(
 
 /*
  * This is called to pin the buffer associated with the buf log item in memory
- * so it cannot be written out.  Simply call bpin() on the buffer to do this.
+ * so it cannot be written out.
  *
  * We also always take a reference to the buffer log item here so that the bli
  * is held while the item is pinned in memory. This means that we can
  * unconditionally drop the reference count a transaction holds when the
  * transaction is completed.
  */
-
 STATIC void
 xfs_buf_item_pin(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip)
 {
-       xfs_buf_t       *bp;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
 
-       bp = bip->bli_buf;
-       ASSERT(XFS_BUF_ISBUSY(bp));
+       ASSERT(XFS_BUF_ISBUSY(bip->bli_buf));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
               (bip->bli_flags & XFS_BLI_STALE));
-       atomic_inc(&bip->bli_refcount);
+
        trace_xfs_buf_item_pin(bip);
-       xfs_bpin(bp);
-}
 
+       atomic_inc(&bip->bli_refcount);
+       atomic_inc(&bip->bli_buf->b_pin_count);
+}
 
 /*
  * This is called to unpin the buffer associated with the buf log
  * item which was previously pinned with a call to xfs_buf_item_pin().
- * Just call bunpin() on the buffer to do this.
  *
  * Also drop the reference to the buf item for the current transaction.
  * If the XFS_BLI_STALE flag is set and we are the last reference,
  * then free up the buf log item and unlock the buffer.
+ *
+ * If the remove flag is set we are called from uncommit in the
+ * forced-shutdown path.  If that is true and the reference count on
+ * the log item is going to drop to zero we need to free the item's
+ * descriptor in the transaction.
  */
 STATIC void
 xfs_buf_item_unpin(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip,
+       int                     remove)
 {
-       struct xfs_ail  *ailp;
-       xfs_buf_t       *bp;
-       int             freed;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       xfs_buf_t       *bp = bip->bli_buf;
+       struct xfs_ail  *ailp = lip->li_ailp;
        int             stale = bip->bli_flags & XFS_BLI_STALE;
+       int             freed;
 
-       bp = bip->bli_buf;
-       ASSERT(bp != NULL);
        ASSERT(XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *) == bip);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
+
        trace_xfs_buf_item_unpin(bip);
 
        freed = atomic_dec_and_test(&bip->bli_refcount);
-       ailp = bip->bli_item.li_ailp;
-       xfs_bunpin(bp);
+
+       if (atomic_dec_and_test(&bp->b_pin_count))
+               wake_up_all(&bp->b_waiters);
+
        if (freed && stale) {
                ASSERT(bip->bli_flags & XFS_BLI_STALE);
                ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
                ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
                ASSERT(XFS_BUF_ISSTALE(bp));
                ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+
                trace_xfs_buf_item_unpin_stale(bip);
 
+               if (remove) {
+                       /*
+                        * We have to remove the log item from the transaction
+                        * as we are about to release our reference to the
+                        * buffer.  If we don't, the unlock that occurs later
+                        * in xfs_trans_uncommit() will ry to reference the
+                        * buffer which we no longer have a hold on.
+                        */
+                       xfs_trans_del_item(lip);
+
+                       /*
+                        * Since the transaction no longer refers to the buffer,
+                        * the buffer should no longer refer to the transaction.
+                        */
+                       XFS_BUF_SET_FSPRIVATE2(bp, NULL);
+               }
+
                /*
                 * If we get called here because of an IO error, we may
                 * or may not have the item on the AIL. xfs_trans_ail_delete()
@@ -436,48 +463,6 @@ xfs_buf_item_unpin(
        }
 }
 
-/*
- * this is called from uncommit in the forced-shutdown path.
- * we need to check to see if the reference count on the log item
- * is going to drop to zero.  If so, unpin will free the log item
- * so we need to free the item's descriptor (that points to the item)
- * in the transaction.
- */
-STATIC void
-xfs_buf_item_unpin_remove(
-       xfs_buf_log_item_t      *bip,
-       xfs_trans_t             *tp)
-{
-       /* will xfs_buf_item_unpin() call xfs_buf_item_relse()? */
-       if ((atomic_read(&bip->bli_refcount) == 1) &&
-           (bip->bli_flags & XFS_BLI_STALE)) {
-               /*
-                * yes -- We can safely do some work here and then call
-                * buf_item_unpin to do the rest because we are
-                * are holding the buffer locked so no one else will be
-                * able to bump up the refcount. We have to remove the
-                * log item from the transaction as we are about to release
-                * our reference to the buffer. If we don't, the unlock that
-                * occurs later in the xfs_trans_uncommit() will try to
-                * reference the buffer which we no longer have a hold on.
-                */
-               struct xfs_log_item_desc *lidp;
-
-               ASSERT(XFS_BUF_VALUSEMA(bip->bli_buf) <= 0);
-               trace_xfs_buf_item_unpin_stale(bip);
-
-               lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)bip);
-               xfs_trans_free_item(tp, lidp);
-
-               /*
-                * Since the transaction no longer refers to the buffer, the
-                * buffer should no longer refer to the transaction.
-                */
-               XFS_BUF_SET_FSPRIVATE2(bip->bli_buf, NULL);
-       }
-       xfs_buf_item_unpin(bip);
-}
-
 /*
  * This is called to attempt to lock the buffer associated with this
  * buf log item.  Don't sleep on the buffer lock.  If we can't get
@@ -488,11 +473,11 @@ xfs_buf_item_unpin_remove(
  */
 STATIC uint
 xfs_buf_item_trylock(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip)
 {
-       xfs_buf_t       *bp;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf          *bp = bip->bli_buf;
 
-       bp = bip->bli_buf;
        if (XFS_BUF_ISPINNED(bp))
                return XFS_ITEM_PINNED;
        if (!XFS_BUF_CPSEMA(bp))
@@ -529,13 +514,12 @@ xfs_buf_item_trylock(
  */
 STATIC void
 xfs_buf_item_unlock(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip)
 {
-       int             aborted;
-       xfs_buf_t       *bp;
-       uint            hold;
-
-       bp = bip->bli_buf;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf          *bp = bip->bli_buf;
+       int                     aborted;
+       uint                    hold;
 
        /* Clear the buffer's association with this transaction. */
        XFS_BUF_SET_FSPRIVATE2(bp, NULL);
@@ -546,7 +530,7 @@ xfs_buf_item_unlock(
         * (cancelled) buffers at unpin time, but we'll never go through the
         * pin/unpin cycle if we abort inside commit.
         */
-       aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0;
+       aborted = (lip->li_flags & XFS_LI_ABORTED) != 0;
 
        /*
         * Before possibly freeing the buf item, determine if we should
@@ -607,16 +591,16 @@ xfs_buf_item_unlock(
  */
 STATIC xfs_lsn_t
 xfs_buf_item_committed(
-       xfs_buf_log_item_t      *bip,
+       struct xfs_log_item     *lip,
        xfs_lsn_t               lsn)
 {
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+
        trace_xfs_buf_item_committed(bip);
 
-       if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
-           (bip->bli_item.li_lsn != 0)) {
-               return bip->bli_item.li_lsn;
-       }
-       return (lsn);
+       if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && lip->li_lsn != 0)
+               return lip->li_lsn;
+       return lsn;
 }
 
 /*
@@ -626,15 +610,16 @@ xfs_buf_item_committed(
  */
 STATIC void
 xfs_buf_item_push(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip)
 {
-       xfs_buf_t       *bp;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf          *bp = bip->bli_buf;
 
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
+       ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
+
        trace_xfs_buf_item_push(bip);
 
-       bp = bip->bli_buf;
-       ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
        xfs_buf_relse(bp);
 }
 
@@ -646,22 +631,24 @@ xfs_buf_item_push(
  */
 STATIC void
 xfs_buf_item_pushbuf(
-       xfs_buf_log_item_t      *bip)
+       struct xfs_log_item     *lip)
 {
-       xfs_buf_t       *bp;
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf          *bp = bip->bli_buf;
 
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
+       ASSERT(XFS_BUF_ISDELAYWRITE(bp));
+
        trace_xfs_buf_item_pushbuf(bip);
 
-       bp = bip->bli_buf;
-       ASSERT(XFS_BUF_ISDELAYWRITE(bp));
        xfs_buf_delwri_promote(bp);
        xfs_buf_relse(bp);
 }
 
-/* ARGSUSED */
 STATIC void
-xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn)
+xfs_buf_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               commit_lsn)
 {
 }
 
@@ -669,21 +656,16 @@ xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn)
  * This is the ops vector shared by all buf log items.
  */
 static struct xfs_item_ops xfs_buf_item_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_buf_item_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_buf_item_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_buf_item_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_buf_item_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *))
-                                       xfs_buf_item_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_buf_item_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_buf_item_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_buf_item_push,
-       .iop_pushbuf    = (void(*)(xfs_log_item_t*))xfs_buf_item_pushbuf,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_buf_item_committing
+       .iop_size       = xfs_buf_item_size,
+       .iop_format     = xfs_buf_item_format,
+       .iop_pin        = xfs_buf_item_pin,
+       .iop_unpin      = xfs_buf_item_unpin,
+       .iop_trylock    = xfs_buf_item_trylock,
+       .iop_unlock     = xfs_buf_item_unlock,
+       .iop_committed  = xfs_buf_item_committed,
+       .iop_push       = xfs_buf_item_push,
+       .iop_pushbuf    = xfs_buf_item_pushbuf,
+       .iop_committing = xfs_buf_item_committing
 };
 
 
@@ -712,7 +694,6 @@ xfs_buf_item_init(
         */
        if (bp->b_mount != mp)
                bp->b_mount = mp;
-       XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb);
        if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) {
                lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
                if (lip->li_type == XFS_LI_BUF) {
@@ -1098,15 +1079,14 @@ xfs_buf_error_relse(
  * It is called by xfs_buf_iodone_callbacks() above which will take
  * care of cleaning up the buffer itself.
  */
-/* ARGSUSED */
 void
 xfs_buf_iodone(
-       xfs_buf_t               *bp,
-       xfs_buf_log_item_t      *bip)
+       struct xfs_buf          *bp,
+       struct xfs_log_item     *lip)
 {
-       struct xfs_ail          *ailp = bip->bli_item.li_ailp;
+       struct xfs_ail          *ailp = lip->li_ailp;
 
-       ASSERT(bip->bli_buf == bp);
+       ASSERT(BUF_ITEM(lip)->bli_buf == bp);
 
        xfs_buf_rele(bp);
 
@@ -1120,6 +1100,6 @@ xfs_buf_iodone(
         * Either way, AIL is useless if we're forcing a shutdown.
         */
        spin_lock(&ailp->xa_lock);
-       xfs_trans_ail_delete(ailp, (xfs_log_item_t *)bip);
-       xfs_buf_item_free(bip);
+       xfs_trans_ail_delete(ailp, lip);
+       xfs_buf_item_free(BUF_ITEM(lip));
 }
index f20bb472d582f1e5b711c1593958b3593ad2167c..0e2ed43f16c71ace4bde6152ef2eca33b2fa966d 100644 (file)
@@ -124,7 +124,7 @@ void        xfs_buf_attach_iodone(struct xfs_buf *,
                              void(*)(struct xfs_buf *, xfs_log_item_t *),
                              xfs_log_item_t *);
 void   xfs_buf_iodone_callbacks(struct xfs_buf *);
-void   xfs_buf_iodone(struct xfs_buf *, xfs_buf_log_item_t *);
+void   xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);
 
 #ifdef XFS_TRANS_DEBUG
 void
index 0ca556b4bf313bf8526769ff051f188df5a3066e..30fa0e206fba84a5279ed9f92f6c9b7035484f47 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_alloc.h"
-#include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
@@ -581,16 +576,14 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        xfs_da_intnode_t *node;
        xfs_da_node_entry_t *btree;
        int tmp;
-       xfs_mount_t *mp;
 
        node = oldblk->bp->data;
-       mp = state->mp;
        ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
        ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
        ASSERT(newblk->blkno != 0);
        if (state->args->whichfork == XFS_DATA_FORK)
-               ASSERT(newblk->blkno >= mp->m_dirleafblk &&
-                      newblk->blkno < mp->m_dirfreeblk);
+               ASSERT(newblk->blkno >= state->mp->m_dirleafblk &&
+                      newblk->blkno < state->mp->m_dirfreeblk);
 
        /*
         * We may need to make some room before we insert the new node.
@@ -1601,7 +1594,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
                        xfs_bmapi_aflag(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|
                        XFS_BMAPI_CONTIG,
                        args->firstblock, args->total, &map, &nmap,
-                       args->flist, NULL))) {
+                       args->flist))) {
                return error;
        }
        ASSERT(nmap <= 1);
@@ -1622,8 +1615,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
                                        xfs_bmapi_aflag(w)|XFS_BMAPI_WRITE|
                                        XFS_BMAPI_METADATA,
                                        args->firstblock, args->total,
-                                       &mapp[mapi], &nmap, args->flist,
-                                       NULL))) {
+                                       &mapp[mapi], &nmap, args->flist))) {
                                kmem_free(mapp);
                                return error;
                        }
@@ -1884,7 +1876,7 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
                 */
                if ((error = xfs_bunmapi(tp, dp, dead_blkno, count,
                                xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA,
-                               0, args->firstblock, args->flist, NULL,
+                               0, args->firstblock, args->flist,
                                &done)) == ENOSPC) {
                        if (w != XFS_DATA_FORK)
                                break;
@@ -1989,7 +1981,7 @@ xfs_da_do_buf(
                                        nfsb,
                                        XFS_BMAPI_METADATA |
                                                xfs_bmapi_aflag(whichfork),
-                                       NULL, 0, mapp, &nmap, NULL, NULL)))
+                                       NULL, 0, mapp, &nmap, NULL)))
                                goto exit0;
                }
        } else {
index 7f159d2a429a97e8a71e0fd57298ec499519c064..3b9582c60a225117f7b6d4180e4287b0118375ed 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_dfrag.h"
 #include "xfs_error.h"
-#include "xfs_rw.h"
 #include "xfs_vnodeops.h"
 #include "xfs_trace.h"
 
@@ -425,11 +416,8 @@ xfs_swap_extents(
        }
 
 
-       IHOLD(ip);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
-       IHOLD(tip);
-       xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
        xfs_trans_log_inode(tp, ip,  ilf_fields);
        xfs_trans_log_inode(tp, tip, tilf_fields);
index 42520f041265fea2d7df1d02bc8a4e3e82215337..a1321bc7f19210a3b4bd1d87ec7c9d5eae410b28 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
@@ -382,7 +380,7 @@ xfs_readdir(
        int             rval;           /* return value */
        int             v;              /* type-checking value */
 
-       xfs_itrace_entry(dp);
+       trace_xfs_readdir(dp);
 
        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
                return XFS_ERROR(EIO);
@@ -549,7 +547,7 @@ xfs_dir2_grow_inode(
        if ((error = xfs_bmapi(tp, dp, bno, count,
                        XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
                        args->firstblock, args->total, &map, &nmap,
-                       args->flist, NULL)))
+                       args->flist)))
                return error;
        ASSERT(nmap <= 1);
        if (nmap == 1) {
@@ -581,8 +579,7 @@ xfs_dir2_grow_inode(
                        if ((error = xfs_bmapi(tp, dp, b, c,
                                        XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
                                        args->firstblock, args->total,
-                                       &mapp[mapi], &nmap, args->flist,
-                                       NULL))) {
+                                       &mapp[mapi], &nmap, args->flist))) {
                                kmem_free(mapp);
                                return error;
                        }
@@ -715,7 +712,7 @@ xfs_dir2_shrink_inode(
         */
        if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
                        XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
-                       NULL, &done))) {
+                       &done))) {
                /*
                 * ENOSPC actually can happen if we're in a removename with
                 * no space reservation, and the resulting block removal
index 779a267b0a84c55a83764d25d469493b24ca0a7f..580d99cef9e7bb25a4344343cf080df23b3e51a3 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
@@ -1073,10 +1071,10 @@ xfs_dir2_sf_to_block(
         */
 
        buf_len = dp->i_df.if_bytes;
-       buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
+       buf = kmem_alloc(buf_len, KM_SLEEP);
 
-       memcpy(buf, sfp, dp->i_df.if_bytes);
-       xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
+       memcpy(buf, sfp, buf_len);
+       xfs_idata_realloc(dp, -buf_len, XFS_DATA_FORK);
        dp->i_d.di_size = 0;
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
        /*
index 498f8d694330dba475aad5c1c1d1147f73bfab9c..921595b84f5bc613835c1e05601875b46b16c871 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_dir2_data.h"
index e2d89854ec9ec4649f2016d3c2592832bb5ee403..504be8640e918250d5ea58a6df3d64c223655187 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -875,7 +873,7 @@ xfs_dir2_leaf_getdents(
                                        xfs_dir2_byte_to_da(mp,
                                                XFS_DIR2_LEAF_OFFSET) - map_off,
                                        XFS_BMAPI_METADATA, NULL, 0,
-                                       &map[map_valid], &nmap, NULL, NULL);
+                                       &map[map_valid], &nmap, NULL);
                                /*
                                 * Don't know if we should ignore this or
                                 * try to return an error.
index 78fc4d9ae7562d02ea2068132ac44a81e9dfa776..f9a0864b696afea29fec8567a906ac793c882455 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
index c1a5945d463a3d4ff3abd6aca0beb42f535f6988..b1bae6b1eed9b730ba8dba261e1755fcf207c10c 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h
deleted file mode 100644 (file)
index 2813cdd..0000000
+++ /dev/null
@@ -1,170 +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_DMAPI_H__
-#define __XFS_DMAPI_H__
-
-/*     Values used to define the on-disk version of dm_attrname_t. All
- *     on-disk attribute names start with the 8-byte string "SGI_DMI_".
- *
- *      In the on-disk inode, DMAPI attribute names consist of the user-provided
- *      name with the DMATTR_PREFIXSTRING pre-pended.  This string must NEVER be
- *      changed.
- */
-
-#define DMATTR_PREFIXLEN       8
-#define DMATTR_PREFIXSTRING    "SGI_DMI_"
-
-typedef enum {
-       DM_EVENT_INVALID        = -1,
-       DM_EVENT_CANCEL         = 0,            /* not supported */
-       DM_EVENT_MOUNT          = 1,
-       DM_EVENT_PREUNMOUNT     = 2,
-       DM_EVENT_UNMOUNT        = 3,
-       DM_EVENT_DEBUT          = 4,            /* not supported */
-       DM_EVENT_CREATE         = 5,
-       DM_EVENT_CLOSE          = 6,            /* not supported */
-       DM_EVENT_POSTCREATE     = 7,
-       DM_EVENT_REMOVE         = 8,
-       DM_EVENT_POSTREMOVE     = 9,
-       DM_EVENT_RENAME         = 10,
-       DM_EVENT_POSTRENAME     = 11,
-       DM_EVENT_LINK           = 12,
-       DM_EVENT_POSTLINK       = 13,
-       DM_EVENT_SYMLINK        = 14,
-       DM_EVENT_POSTSYMLINK    = 15,
-       DM_EVENT_READ           = 16,
-       DM_EVENT_WRITE          = 17,
-       DM_EVENT_TRUNCATE       = 18,
-       DM_EVENT_ATTRIBUTE      = 19,
-       DM_EVENT_DESTROY        = 20,
-       DM_EVENT_NOSPACE        = 21,
-       DM_EVENT_USER           = 22,
-       DM_EVENT_MAX            = 23
-} dm_eventtype_t;
-#define HAVE_DM_EVENTTYPE_T
-
-typedef enum {
-       DM_RIGHT_NULL,
-       DM_RIGHT_SHARED,
-       DM_RIGHT_EXCL
-} dm_right_t;
-#define HAVE_DM_RIGHT_T
-
-/* Defines for determining if an event message should be sent. */
-#ifdef HAVE_DMAPI
-#define        DM_EVENT_ENABLED(ip, event) ( \
-       unlikely ((ip)->i_mount->m_flags & XFS_MOUNT_DMAPI) && \
-               ( ((ip)->i_d.di_dmevmask & (1 << event)) || \
-                 ((ip)->i_mount->m_dmevmask & (1 << event)) ) \
-       )
-#else
-#define DM_EVENT_ENABLED(ip, event)    (0)
-#endif
-
-#define DM_XFS_VALID_FS_EVENTS         ( \
-       (1 << DM_EVENT_PREUNMOUNT)      | \
-       (1 << DM_EVENT_UNMOUNT)         | \
-       (1 << DM_EVENT_NOSPACE)         | \
-       (1 << DM_EVENT_DEBUT)           | \
-       (1 << DM_EVENT_CREATE)          | \
-       (1 << DM_EVENT_POSTCREATE)      | \
-       (1 << DM_EVENT_REMOVE)          | \
-       (1 << DM_EVENT_POSTREMOVE)      | \
-       (1 << DM_EVENT_RENAME)          | \
-       (1 << DM_EVENT_POSTRENAME)      | \
-       (1 << DM_EVENT_LINK)            | \
-       (1 << DM_EVENT_POSTLINK)        | \
-       (1 << DM_EVENT_SYMLINK)         | \
-       (1 << DM_EVENT_POSTSYMLINK)     | \
-       (1 << DM_EVENT_ATTRIBUTE)       | \
-       (1 << DM_EVENT_DESTROY)         )
-
-/* Events valid in dm_set_eventlist() when called with a file handle for
-   a regular file or a symlink.  These events are persistent.
-*/
-
-#define        DM_XFS_VALID_FILE_EVENTS        ( \
-       (1 << DM_EVENT_ATTRIBUTE)       | \
-       (1 << DM_EVENT_DESTROY)         )
-
-/* Events valid in dm_set_eventlist() when called with a file handle for
-   a directory.  These events are persistent.
-*/
-
-#define        DM_XFS_VALID_DIRECTORY_EVENTS   ( \
-       (1 << DM_EVENT_CREATE)          | \
-       (1 << DM_EVENT_POSTCREATE)      | \
-       (1 << DM_EVENT_REMOVE)          | \
-       (1 << DM_EVENT_POSTREMOVE)      | \
-       (1 << DM_EVENT_RENAME)          | \
-       (1 << DM_EVENT_POSTRENAME)      | \
-       (1 << DM_EVENT_LINK)            | \
-       (1 << DM_EVENT_POSTLINK)        | \
-       (1 << DM_EVENT_SYMLINK)         | \
-       (1 << DM_EVENT_POSTSYMLINK)     | \
-       (1 << DM_EVENT_ATTRIBUTE)       | \
-       (1 << DM_EVENT_DESTROY)         )
-
-/* Events supported by the XFS filesystem. */
-#define        DM_XFS_SUPPORTED_EVENTS         ( \
-       (1 << DM_EVENT_MOUNT)           | \
-       (1 << DM_EVENT_PREUNMOUNT)      | \
-       (1 << DM_EVENT_UNMOUNT)         | \
-       (1 << DM_EVENT_NOSPACE)         | \
-       (1 << DM_EVENT_CREATE)          | \
-       (1 << DM_EVENT_POSTCREATE)      | \
-       (1 << DM_EVENT_REMOVE)          | \
-       (1 << DM_EVENT_POSTREMOVE)      | \
-       (1 << DM_EVENT_RENAME)          | \
-       (1 << DM_EVENT_POSTRENAME)      | \
-       (1 << DM_EVENT_LINK)            | \
-       (1 << DM_EVENT_POSTLINK)        | \
-       (1 << DM_EVENT_SYMLINK)         | \
-       (1 << DM_EVENT_POSTSYMLINK)     | \
-       (1 << DM_EVENT_READ)            | \
-       (1 << DM_EVENT_WRITE)           | \
-       (1 << DM_EVENT_TRUNCATE)        | \
-       (1 << DM_EVENT_ATTRIBUTE)       | \
-       (1 << DM_EVENT_DESTROY)         )
-
-
-/*
- *     Definitions used for the flags field on dm_send_*_event().
- */
-
-#define DM_FLAGS_NDELAY                0x001   /* return EAGAIN after dm_pending() */
-#define DM_FLAGS_UNWANTED      0x002   /* event not in fsys dm_eventset_t */
-#define DM_FLAGS_IMUX          0x004   /* thread holds i_mutex */
-#define DM_FLAGS_IALLOCSEM_RD  0x010   /* thread holds i_alloc_sem rd */
-#define DM_FLAGS_IALLOCSEM_WR  0x020   /* thread holds i_alloc_sem wr */
-
-/*
- *     Pull in platform specific event flags defines
- */
-#include "xfs_dmapi_priv.h"
-
-/*
- *     Macros to turn caller specified delay/block flags into
- *     dm_send_xxxx_event flag DM_FLAGS_NDELAY.
- */
-
-#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
-                       DM_FLAGS_NDELAY : 0)
-#define AT_DELAY_FLAG(f) ((f & XFS_ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
-
-#endif  /* __XFS_DMAPI_H__ */
diff --git a/fs/xfs/xfs_dmops.c b/fs/xfs/xfs_dmops.c
deleted file mode 100644 (file)
index e71e258..0000000
+++ /dev/null
@@ -1,55 +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 "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_dmapi.h"
-#include "xfs_inum.h"
-#include "xfs_ag.h"
-#include "xfs_mount.h"
-
-
-static struct xfs_dmops xfs_dmcore_stub = {
-       .xfs_send_data          = (xfs_send_data_t)fs_nosys,
-       .xfs_send_mmap          = (xfs_send_mmap_t)fs_noerr,
-       .xfs_send_destroy       = (xfs_send_destroy_t)fs_nosys,
-       .xfs_send_namesp        = (xfs_send_namesp_t)fs_nosys,
-       .xfs_send_mount         = (xfs_send_mount_t)fs_nosys,
-       .xfs_send_unmount       = (xfs_send_unmount_t)fs_noerr,
-};
-
-int
-xfs_dmops_get(struct xfs_mount *mp)
-{
-       if (mp->m_flags & XFS_MOUNT_DMAPI) {
-               cmn_err(CE_WARN,
-                       "XFS: dmapi support not available in this kernel.");
-               return EINVAL;
-       }
-
-       mp->m_dm_ops = &xfs_dmcore_stub;
-       return 0;
-}
-
-void
-xfs_dmops_put(struct xfs_mount *mp)
-{
-}
index 047b8a8e5c294856f861251a4cbfa7a7ec0d00fc..ed99902676615e166a8e08371bf79c3a33d98021 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_utils.h"
index 409fe81585fdbb38ea66546c01c4dc74922464b3..a55e687bf562f1174e37e0764e9dab1405333a7a 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_buf_item.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
 #include "xfs_extfree_item.h"
 kmem_zone_t    *xfs_efi_zone;
 kmem_zone_t    *xfs_efd_zone;
 
-STATIC void    xfs_efi_item_unlock(xfs_efi_log_item_t *);
+static inline struct xfs_efi_log_item *EFI_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_efi_log_item, efi_item);
+}
 
 void
-xfs_efi_item_free(xfs_efi_log_item_t *efip)
+xfs_efi_item_free(
+       struct xfs_efi_log_item *efip)
 {
-       int nexts = efip->efi_format.efi_nextents;
-
-       if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
+       if (efip->efi_format.efi_nextents > XFS_EFI_MAX_FAST_EXTENTS)
                kmem_free(efip);
-       } else {
+       else
                kmem_zone_free(xfs_efi_zone, efip);
-       }
 }
 
 /*
@@ -52,9 +52,9 @@ xfs_efi_item_free(xfs_efi_log_item_t *efip)
  * We only need 1 iovec for an efi item.  It just logs the efi_log_format
  * structure.
  */
-/*ARGSUSED*/
 STATIC uint
-xfs_efi_item_size(xfs_efi_log_item_t *efip)
+xfs_efi_item_size(
+       struct xfs_log_item     *lip)
 {
        return 1;
 }
@@ -67,10 +67,12 @@ xfs_efi_item_size(xfs_efi_log_item_t *efip)
  * slots in the efi item have been filled.
  */
 STATIC void
-xfs_efi_item_format(xfs_efi_log_item_t *efip,
-                   xfs_log_iovec_t     *log_vector)
+xfs_efi_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *log_vector)
 {
-       uint    size;
+       struct xfs_efi_log_item *efip = EFI_ITEM(lip);
+       uint                    size;
 
        ASSERT(efip->efi_next_extent == efip->efi_format.efi_nextents);
 
@@ -80,7 +82,7 @@ xfs_efi_item_format(xfs_efi_log_item_t        *efip,
        size += (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t);
        efip->efi_format.efi_size = 1;
 
-       log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format);
+       log_vector->i_addr = &efip->efi_format;
        log_vector->i_len = size;
        log_vector->i_type = XLOG_REG_TYPE_EFI_FORMAT;
        ASSERT(size >= sizeof(xfs_efi_log_format_t));
@@ -90,60 +92,33 @@ xfs_efi_item_format(xfs_efi_log_item_t      *efip,
 /*
  * Pinning has no meaning for an efi item, so just return.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efi_item_pin(xfs_efi_log_item_t *efip)
+xfs_efi_item_pin(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
-
 /*
  * While EFIs cannot really be pinned, the unpin operation is the
  * last place at which the EFI is manipulated during a transaction.
  * Here we coordinate with xfs_efi_cancel() to determine who gets to
  * free the EFI.
  */
-/*ARGSUSED*/
-STATIC void
-xfs_efi_item_unpin(xfs_efi_log_item_t *efip)
-{
-       struct xfs_ail          *ailp = efip->efi_item.li_ailp;
-
-       spin_lock(&ailp->xa_lock);
-       if (efip->efi_flags & XFS_EFI_CANCELED) {
-               /* xfs_trans_ail_delete() drops the AIL lock. */
-               xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
-               xfs_efi_item_free(efip);
-       } else {
-               efip->efi_flags |= XFS_EFI_COMMITTED;
-               spin_unlock(&ailp->xa_lock);
-       }
-}
-
-/*
- * like unpin only we have to also clear the xaction descriptor
- * pointing the log item if we free the item.  This routine duplicates
- * unpin because efi_flags is protected by the AIL lock.  Freeing
- * the descriptor and then calling unpin would force us to drop the AIL
- * lock which would open up a race condition.
- */
 STATIC void
-xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp)
+xfs_efi_item_unpin(
+       struct xfs_log_item     *lip,
+       int                     remove)
 {
-       struct xfs_ail          *ailp = efip->efi_item.li_ailp;
-       xfs_log_item_desc_t     *lidp;
+       struct xfs_efi_log_item *efip = EFI_ITEM(lip);
+       struct xfs_ail          *ailp = lip->li_ailp;
 
        spin_lock(&ailp->xa_lock);
        if (efip->efi_flags & XFS_EFI_CANCELED) {
-               /*
-                * free the xaction descriptor pointing to this item
-                */
-               lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip);
-               xfs_trans_free_item(tp, lidp);
+               if (remove)
+                       xfs_trans_del_item(lip);
 
                /* xfs_trans_ail_delete() drops the AIL lock. */
-               xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
+               xfs_trans_ail_delete(ailp, lip);
                xfs_efi_item_free(efip);
        } else {
                efip->efi_flags |= XFS_EFI_COMMITTED;
@@ -158,9 +133,9 @@ xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp)
  * XFS_ITEM_PINNED so that the caller will eventually flush the log.
  * This should help in getting the EFI out of the AIL.
  */
-/*ARGSUSED*/
 STATIC uint
-xfs_efi_item_trylock(xfs_efi_log_item_t *efip)
+xfs_efi_item_trylock(
+       struct xfs_log_item     *lip)
 {
        return XFS_ITEM_PINNED;
 }
@@ -168,13 +143,12 @@ xfs_efi_item_trylock(xfs_efi_log_item_t *efip)
 /*
  * Efi items have no locking, so just return.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efi_item_unlock(xfs_efi_log_item_t *efip)
+xfs_efi_item_unlock(
+       struct xfs_log_item     *lip)
 {
-       if (efip->efi_item.li_flags & XFS_LI_ABORTED)
-               xfs_efi_item_free(efip);
-       return;
+       if (lip->li_flags & XFS_LI_ABORTED)
+               xfs_efi_item_free(EFI_ITEM(lip));
 }
 
 /*
@@ -183,9 +157,10 @@ xfs_efi_item_unlock(xfs_efi_log_item_t *efip)
  * flag is not paid any attention here.  Checking for that is delayed
  * until the EFI is unpinned.
  */
-/*ARGSUSED*/
 STATIC xfs_lsn_t
-xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
+xfs_efi_item_committed(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
 {
        return lsn;
 }
@@ -195,11 +170,10 @@ xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
  * stuck waiting for all of its corresponding efd items to be
  * committed to disk.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efi_item_push(xfs_efi_log_item_t *efip)
+xfs_efi_item_push(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
 /*
@@ -209,61 +183,55 @@ xfs_efi_item_push(xfs_efi_log_item_t *efip)
  * example, for inodes, the inode is locked throughout the extent freeing
  * so the dependency should be recorded there.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
+xfs_efi_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
 {
-       return;
 }
 
 /*
  * This is the ops vector shared by all efi log items.
  */
 static struct xfs_item_ops xfs_efi_item_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_efi_item_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_efi_item_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_efi_item_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_efi_item_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *))
-                                       xfs_efi_item_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_efi_item_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_efi_item_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_efi_item_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_efi_item_push,
-       .iop_pushbuf    = NULL,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_efi_item_committing
+       .iop_size       = xfs_efi_item_size,
+       .iop_format     = xfs_efi_item_format,
+       .iop_pin        = xfs_efi_item_pin,
+       .iop_unpin      = xfs_efi_item_unpin,
+       .iop_trylock    = xfs_efi_item_trylock,
+       .iop_unlock     = xfs_efi_item_unlock,
+       .iop_committed  = xfs_efi_item_committed,
+       .iop_push       = xfs_efi_item_push,
+       .iop_committing = xfs_efi_item_committing
 };
 
 
 /*
  * Allocate and initialize an efi item with the given number of extents.
  */
-xfs_efi_log_item_t *
-xfs_efi_init(xfs_mount_t       *mp,
-            uint               nextents)
+struct xfs_efi_log_item *
+xfs_efi_init(
+       struct xfs_mount        *mp,
+       uint                    nextents)
 
 {
-       xfs_efi_log_item_t      *efip;
+       struct xfs_efi_log_item *efip;
        uint                    size;
 
        ASSERT(nextents > 0);
        if (nextents > XFS_EFI_MAX_FAST_EXTENTS) {
                size = (uint)(sizeof(xfs_efi_log_item_t) +
                        ((nextents - 1) * sizeof(xfs_extent_t)));
-               efip = (xfs_efi_log_item_t*)kmem_zalloc(size, KM_SLEEP);
+               efip = kmem_zalloc(size, KM_SLEEP);
        } else {
-               efip = (xfs_efi_log_item_t*)kmem_zone_zalloc(xfs_efi_zone,
-                                                            KM_SLEEP);
+               efip = kmem_zone_zalloc(xfs_efi_zone, KM_SLEEP);
        }
 
        xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops);
        efip->efi_format.efi_nextents = nextents;
        efip->efi_format.efi_id = (__psint_t)(void*)efip;
 
-       return (efip);
+       return efip;
 }
 
 /*
@@ -276,7 +244,7 @@ xfs_efi_init(xfs_mount_t    *mp,
 int
 xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
 {
-       xfs_efi_log_format_t *src_efi_fmt = (xfs_efi_log_format_t *)buf->i_addr;
+       xfs_efi_log_format_t *src_efi_fmt = buf->i_addr;
        uint i;
        uint len = sizeof(xfs_efi_log_format_t) + 
                (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t);  
@@ -289,8 +257,7 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
                memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len);
                return 0;
        } else if (buf->i_len == len32) {
-               xfs_efi_log_format_32_t *src_efi_fmt_32 =
-                       (xfs_efi_log_format_32_t *)buf->i_addr;
+               xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->i_addr;
 
                dst_efi_fmt->efi_type     = src_efi_fmt_32->efi_type;
                dst_efi_fmt->efi_size     = src_efi_fmt_32->efi_size;
@@ -304,8 +271,7 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
                }
                return 0;
        } else if (buf->i_len == len64) {
-               xfs_efi_log_format_64_t *src_efi_fmt_64 =
-                       (xfs_efi_log_format_64_t *)buf->i_addr;
+               xfs_efi_log_format_64_t *src_efi_fmt_64 = buf->i_addr;
 
                dst_efi_fmt->efi_type     = src_efi_fmt_64->efi_type;
                dst_efi_fmt->efi_size     = src_efi_fmt_64->efi_size;
@@ -356,16 +322,18 @@ xfs_efi_release(xfs_efi_log_item_t        *efip,
        }
 }
 
-STATIC void
-xfs_efd_item_free(xfs_efd_log_item_t *efdp)
+static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip)
 {
-       int nexts = efdp->efd_format.efd_nextents;
+       return container_of(lip, struct xfs_efd_log_item, efd_item);
+}
 
-       if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
+STATIC void
+xfs_efd_item_free(struct xfs_efd_log_item *efdp)
+{
+       if (efdp->efd_format.efd_nextents > XFS_EFD_MAX_FAST_EXTENTS)
                kmem_free(efdp);
-       } else {
+       else
                kmem_zone_free(xfs_efd_zone, efdp);
-       }
 }
 
 /*
@@ -373,9 +341,9 @@ xfs_efd_item_free(xfs_efd_log_item_t *efdp)
  * We only need 1 iovec for an efd item.  It just logs the efd_log_format
  * structure.
  */
-/*ARGSUSED*/
 STATIC uint
-xfs_efd_item_size(xfs_efd_log_item_t *efdp)
+xfs_efd_item_size(
+       struct xfs_log_item     *lip)
 {
        return 1;
 }
@@ -388,10 +356,12 @@ xfs_efd_item_size(xfs_efd_log_item_t *efdp)
  * slots in the efd item have been filled.
  */
 STATIC void
-xfs_efd_item_format(xfs_efd_log_item_t *efdp,
-                   xfs_log_iovec_t     *log_vector)
+xfs_efd_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *log_vector)
 {
-       uint    size;
+       struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+       uint                    size;
 
        ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents);
 
@@ -401,48 +371,38 @@ xfs_efd_item_format(xfs_efd_log_item_t    *efdp,
        size += (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t);
        efdp->efd_format.efd_size = 1;
 
-       log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format);
+       log_vector->i_addr = &efdp->efd_format;
        log_vector->i_len = size;
        log_vector->i_type = XLOG_REG_TYPE_EFD_FORMAT;
        ASSERT(size >= sizeof(xfs_efd_log_format_t));
 }
 
-
 /*
  * Pinning has no meaning for an efd item, so just return.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efd_item_pin(xfs_efd_log_item_t *efdp)
+xfs_efd_item_pin(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
-
 /*
  * Since pinning has no meaning for an efd item, unpinning does
  * not either.
  */
-/*ARGSUSED*/
-STATIC void
-xfs_efd_item_unpin(xfs_efd_log_item_t *efdp)
-{
-       return;
-}
-
-/*ARGSUSED*/
 STATIC void
-xfs_efd_item_unpin_remove(xfs_efd_log_item_t *efdp, xfs_trans_t *tp)
+xfs_efd_item_unpin(
+       struct xfs_log_item     *lip,
+       int                     remove)
 {
-       return;
 }
 
 /*
  * Efd items have no locking, so just return success.
  */
-/*ARGSUSED*/
 STATIC uint
-xfs_efd_item_trylock(xfs_efd_log_item_t *efdp)
+xfs_efd_item_trylock(
+       struct xfs_log_item     *lip)
 {
        return XFS_ITEM_LOCKED;
 }
@@ -451,13 +411,12 @@ xfs_efd_item_trylock(xfs_efd_log_item_t *efdp)
  * Efd items have no locking or pushing, so return failure
  * so that the caller doesn't bother with us.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efd_item_unlock(xfs_efd_log_item_t *efdp)
+xfs_efd_item_unlock(
+       struct xfs_log_item     *lip)
 {
-       if (efdp->efd_item.li_flags & XFS_LI_ABORTED)
-               xfs_efd_item_free(efdp);
-       return;
+       if (lip->li_flags & XFS_LI_ABORTED)
+               xfs_efd_item_free(EFD_ITEM(lip));
 }
 
 /*
@@ -467,15 +426,18 @@ xfs_efd_item_unlock(xfs_efd_log_item_t *efdp)
  * return -1 to keep the transaction code from further referencing
  * this item.
  */
-/*ARGSUSED*/
 STATIC xfs_lsn_t
-xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn)
+xfs_efd_item_committed(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
 {
+       struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+
        /*
         * If we got a log I/O error, it's always the case that the LR with the
         * EFI got unpinned and freed before the EFD got aborted.
         */
-       if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0)
+       if (!(lip->li_flags & XFS_LI_ABORTED))
                xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents);
 
        xfs_efd_item_free(efdp);
@@ -486,11 +448,10 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn)
  * There isn't much you can do to push on an efd item.  It is simply
  * stuck waiting for the log to be flushed to disk.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efd_item_push(xfs_efd_log_item_t *efdp)
+xfs_efd_item_push(
+       struct xfs_log_item     *lip)
 {
-       return;
 }
 
 /*
@@ -500,55 +461,48 @@ xfs_efd_item_push(xfs_efd_log_item_t *efdp)
  * example, for inodes, the inode is locked throughout the extent freeing
  * so the dependency should be recorded there.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn)
+xfs_efd_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
 {
-       return;
 }
 
 /*
  * This is the ops vector shared by all efd log items.
  */
 static struct xfs_item_ops xfs_efd_item_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_efd_item_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_efd_item_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_efd_item_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_efd_item_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
-                                       xfs_efd_item_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_efd_item_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_efd_item_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_efd_item_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_efd_item_push,
-       .iop_pushbuf    = NULL,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_efd_item_committing
+       .iop_size       = xfs_efd_item_size,
+       .iop_format     = xfs_efd_item_format,
+       .iop_pin        = xfs_efd_item_pin,
+       .iop_unpin      = xfs_efd_item_unpin,
+       .iop_trylock    = xfs_efd_item_trylock,
+       .iop_unlock     = xfs_efd_item_unlock,
+       .iop_committed  = xfs_efd_item_committed,
+       .iop_push       = xfs_efd_item_push,
+       .iop_committing = xfs_efd_item_committing
 };
 
-
 /*
  * Allocate and initialize an efd item with the given number of extents.
  */
-xfs_efd_log_item_t *
-xfs_efd_init(xfs_mount_t       *mp,
-            xfs_efi_log_item_t *efip,
-            uint               nextents)
+struct xfs_efd_log_item *
+xfs_efd_init(
+       struct xfs_mount        *mp,
+       struct xfs_efi_log_item *efip,
+       uint                    nextents)
 
 {
-       xfs_efd_log_item_t      *efdp;
+       struct xfs_efd_log_item *efdp;
        uint                    size;
 
        ASSERT(nextents > 0);
        if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
                size = (uint)(sizeof(xfs_efd_log_item_t) +
                        ((nextents - 1) * sizeof(xfs_extent_t)));
-               efdp = (xfs_efd_log_item_t*)kmem_zalloc(size, KM_SLEEP);
+               efdp = kmem_zalloc(size, KM_SLEEP);
        } else {
-               efdp = (xfs_efd_log_item_t*)kmem_zone_zalloc(xfs_efd_zone,
-                                                            KM_SLEEP);
+               efdp = kmem_zone_zalloc(xfs_efd_zone, KM_SLEEP);
        }
 
        xfs_log_item_init(mp, &efdp->efd_item, XFS_LI_EFD, &xfs_efd_item_ops);
@@ -556,5 +510,5 @@ xfs_efd_init(xfs_mount_t    *mp,
        efdp->efd_format.efd_nextents = nextents;
        efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;
 
-       return (efdp);
+       return efdp;
 }
index 390850ee6603922651e9ceebfc0f160ce7ff9495..9b715dce5699df0833ea92058683a5b9f30f8868 100644 (file)
 #include "xfs.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inum.h"
-#include "xfs_dir2.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
@@ -127,6 +123,82 @@ typedef struct fstrm_item
        xfs_inode_t     *pip;   /* Parent directory inode pointer. */
 } fstrm_item_t;
 
+/*
+ * Allocation group filestream associations are tracked with per-ag atomic
+ * counters.  These counters allow _xfs_filestream_pick_ag() to tell whether a
+ * particular AG already has active filestreams associated with it. The mount
+ * point's m_peraglock is used to protect these counters from per-ag array
+ * re-allocation during a growfs operation.  When xfs_growfs_data_private() is
+ * about to reallocate the array, it calls xfs_filestream_flush() with the
+ * m_peraglock held in write mode.
+ *
+ * Since xfs_mru_cache_flush() guarantees that all the free functions for all
+ * the cache elements have finished executing before it returns, it's safe for
+ * the free functions to use the atomic counters without m_peraglock protection.
+ * This allows the implementation of xfs_fstrm_free_func() to be agnostic about
+ * whether it was called with the m_peraglock held in read mode, write mode or
+ * not held at all.  The race condition this addresses is the following:
+ *
+ *  - The work queue scheduler fires and pulls a filestream directory cache
+ *    element off the LRU end of the cache for deletion, then gets pre-empted.
+ *  - A growfs operation grabs the m_peraglock in write mode, flushes all the
+ *    remaining items from the cache and reallocates the mount point's per-ag
+ *    array, resetting all the counters to zero.
+ *  - The work queue thread resumes and calls the free function for the element
+ *    it started cleaning up earlier.  In the process it decrements the
+ *    filestreams counter for an AG that now has no references.
+ *
+ * With a shrinkfs feature, the above scenario could panic the system.
+ *
+ * All other uses of the following macros should be protected by either the
+ * m_peraglock held in read mode, or the cache's internal locking exposed by the
+ * interval between a call to xfs_mru_cache_lookup() and a call to
+ * xfs_mru_cache_done().  In addition, the m_peraglock must be held in read mode
+ * when new elements are added to the cache.
+ *
+ * Combined, these locking rules ensure that no associations will ever exist in
+ * the cache that reference per-ag array elements that have since been
+ * reallocated.
+ */
+static int
+xfs_filestream_peek_ag(
+       xfs_mount_t     *mp,
+       xfs_agnumber_t  agno)
+{
+       struct xfs_perag *pag;
+       int             ret;
+
+       pag = xfs_perag_get(mp, agno);
+       ret = atomic_read(&pag->pagf_fstrms);
+       xfs_perag_put(pag);
+       return ret;
+}
+
+static int
+xfs_filestream_get_ag(
+       xfs_mount_t     *mp,
+       xfs_agnumber_t  agno)
+{
+       struct xfs_perag *pag;
+       int             ret;
+
+       pag = xfs_perag_get(mp, agno);
+       ret = atomic_inc_return(&pag->pagf_fstrms);
+       xfs_perag_put(pag);
+       return ret;
+}
+
+static void
+xfs_filestream_put_ag(
+       xfs_mount_t     *mp,
+       xfs_agnumber_t  agno)
+{
+       struct xfs_perag *pag;
+
+       pag = xfs_perag_get(mp, agno);
+       atomic_dec(&pag->pagf_fstrms);
+       xfs_perag_put(pag);
+}
 
 /*
  * Scan the AGs starting at startag looking for an AG that isn't in use and has
@@ -355,16 +427,14 @@ xfs_fstrm_free_func(
 {
        fstrm_item_t    *item  = (fstrm_item_t *)data;
        xfs_inode_t     *ip = item->ip;
-       int ref;
 
        ASSERT(ip->i_ino == ino);
 
        xfs_iflags_clear(ip, XFS_IFILESTREAM);
 
        /* Drop the reference taken on the AG when the item was added. */
-       ref = xfs_filestream_put_ag(ip->i_mount, item->ag);
+       xfs_filestream_put_ag(ip->i_mount, item->ag);
 
-       ASSERT(ref >= 0);
        TRACE_FREE(ip->i_mount, ip, item->pip, item->ag,
                xfs_filestream_peek_ag(ip->i_mount, item->ag));
 
index 260f757bbc5dd0dcea68e6fc6f0200cf2548e930..09dd9af454349b57fe2a8a7bec0f3c5c3c7e4e3e 100644 (file)
@@ -42,88 +42,6 @@ extern ktrace_t *xfs_filestreams_trace_buf;
 
 #endif
 
-/*
- * Allocation group filestream associations are tracked with per-ag atomic
- * counters.  These counters allow _xfs_filestream_pick_ag() to tell whether a
- * particular AG already has active filestreams associated with it. The mount
- * point's m_peraglock is used to protect these counters from per-ag array
- * re-allocation during a growfs operation.  When xfs_growfs_data_private() is
- * about to reallocate the array, it calls xfs_filestream_flush() with the
- * m_peraglock held in write mode.
- *
- * Since xfs_mru_cache_flush() guarantees that all the free functions for all
- * the cache elements have finished executing before it returns, it's safe for
- * the free functions to use the atomic counters without m_peraglock protection.
- * This allows the implementation of xfs_fstrm_free_func() to be agnostic about
- * whether it was called with the m_peraglock held in read mode, write mode or
- * not held at all.  The race condition this addresses is the following:
- *
- *  - The work queue scheduler fires and pulls a filestream directory cache
- *    element off the LRU end of the cache for deletion, then gets pre-empted.
- *  - A growfs operation grabs the m_peraglock in write mode, flushes all the
- *    remaining items from the cache and reallocates the mount point's per-ag
- *    array, resetting all the counters to zero.
- *  - The work queue thread resumes and calls the free function for the element
- *    it started cleaning up earlier.  In the process it decrements the
- *    filestreams counter for an AG that now has no references.
- *
- * With a shrinkfs feature, the above scenario could panic the system.
- *
- * All other uses of the following macros should be protected by either the
- * m_peraglock held in read mode, or the cache's internal locking exposed by the
- * interval between a call to xfs_mru_cache_lookup() and a call to
- * xfs_mru_cache_done().  In addition, the m_peraglock must be held in read mode
- * when new elements are added to the cache.
- *
- * Combined, these locking rules ensure that no associations will ever exist in
- * the cache that reference per-ag array elements that have since been
- * reallocated.
- */
-/*
- * xfs_filestream_peek_ag is only used in tracing code
- */
-static inline int
-xfs_filestream_peek_ag(
-       xfs_mount_t     *mp,
-       xfs_agnumber_t  agno)
-{
-       struct xfs_perag *pag;
-       int             ret;
-
-       pag = xfs_perag_get(mp, agno);
-       ret = atomic_read(&pag->pagf_fstrms);
-       xfs_perag_put(pag);
-       return ret;
-}
-
-static inline int
-xfs_filestream_get_ag(
-       xfs_mount_t     *mp,
-       xfs_agnumber_t  agno)
-{
-       struct xfs_perag *pag;
-       int             ret;
-
-       pag = xfs_perag_get(mp, agno);
-       ret = atomic_inc_return(&pag->pagf_fstrms);
-       xfs_perag_put(pag);
-       return ret;
-}
-
-static inline int
-xfs_filestream_put_ag(
-       xfs_mount_t     *mp,
-       xfs_agnumber_t  agno)
-{
-       struct xfs_perag *pag;
-       int             ret;
-
-       pag = xfs_perag_get(mp, agno);
-       ret = atomic_dec_return(&pag->pagf_fstrms);
-       xfs_perag_put(pag);
-       return ret;
-}
-
 /* allocation selection flags */
 typedef enum xfs_fstrm_alloc {
        XFS_PICK_USERDATA = 1,
index 37a6f62c57b6f89cd93ca38ed6099c5952367401..dbca5f5c37bad18fc220ce21f551d17b58f0c13a 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
@@ -626,8 +622,7 @@ xfs_fs_log_dummy(
        ip = mp->m_rootip;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        xfs_trans_set_sync(tp);
        error = xfs_trans_commit(tp, 0);
index c7142a064c48d7b052d9ac0225f33562d0552386..abf80ae1e95bed43db56f17dd8a7ffc06039a60a 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
index c282a9af5393da36022e471332dc45d37705bcbb..d352862cefa01d7e3c743ed1904b1d1da59bc1b2 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
index 8f8b91be2c996dce5b75901038c507bb4b9ef1da..b1ecc6f97adea06467967178b9a8c6903a41262e 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
@@ -95,7 +91,7 @@ xfs_inode_alloc(
        return ip;
 }
 
-STATIC void
+void
 xfs_inode_free(
        struct xfs_inode        *ip)
 {
@@ -212,7 +208,7 @@ xfs_iget_cache_hit(
                        ip->i_flags &= ~XFS_INEW;
                        ip->i_flags |= XFS_IRECLAIMABLE;
                        __xfs_inode_set_reclaim_tag(pag, ip);
-                       trace_xfs_iget_reclaim(ip);
+                       trace_xfs_iget_reclaim_fail(ip);
                        goto out_error;
                }
 
@@ -227,6 +223,7 @@ xfs_iget_cache_hit(
        } else {
                /* If the VFS inode is being torn down, pause and try again. */
                if (!igrab(inode)) {
+                       trace_xfs_iget_skip(ip);
                        error = EAGAIN;
                        goto out_error;
                }
@@ -234,6 +231,7 @@ xfs_iget_cache_hit(
                /* We've got a live one. */
                spin_unlock(&ip->i_flags_lock);
                read_unlock(&pag->pag_ici_lock);
+               trace_xfs_iget_hit(ip);
        }
 
        if (lock_flags != 0)
@@ -242,7 +240,6 @@ xfs_iget_cache_hit(
        xfs_iflags_clear(ip, XFS_ISTALE);
        XFS_STATS_INC(xs_ig_found);
 
-       trace_xfs_iget_found(ip);
        return 0;
 
 out_error:
@@ -264,7 +261,6 @@ xfs_iget_cache_miss(
 {
        struct xfs_inode        *ip;
        int                     error;
-       unsigned long           first_index, mask;
        xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, ino);
 
        ip = xfs_inode_alloc(mp, ino);
@@ -275,7 +271,7 @@ xfs_iget_cache_miss(
        if (error)
                goto out_destroy;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_iget_miss(ip);
 
        if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
                error = ENOENT;
@@ -301,8 +297,6 @@ xfs_iget_cache_miss(
                        BUG();
        }
 
-       mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
-       first_index = agino & mask;
        write_lock(&pag->pag_ici_lock);
 
        /* insert the new inode */
@@ -321,7 +315,6 @@ xfs_iget_cache_miss(
        write_unlock(&pag->pag_ici_lock);
        radix_tree_preload_end();
 
-       trace_xfs_iget_alloc(ip);
        *ipp = ip;
        return 0;
 
@@ -421,97 +414,6 @@ out_error_or_again:
        return error;
 }
 
-/*
- * Decrement reference count of an inode structure and unlock it.
- *
- * ip -- the inode being released
- * lock_flags -- this parameter indicates the inode's locks to be
- *       to be released.  See the comment on xfs_iunlock() for a list
- *      of valid values.
- */
-void
-xfs_iput(xfs_inode_t   *ip,
-        uint           lock_flags)
-{
-       xfs_itrace_entry(ip);
-       xfs_iunlock(ip, lock_flags);
-       IRELE(ip);
-}
-
-/*
- * Special iput for brand-new inodes that are still locked
- */
-void
-xfs_iput_new(
-       xfs_inode_t     *ip,
-       uint            lock_flags)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       xfs_itrace_entry(ip);
-
-       if ((ip->i_d.di_mode == 0)) {
-               ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE));
-               make_bad_inode(inode);
-       }
-       if (inode->i_state & I_NEW)
-               unlock_new_inode(inode);
-       if (lock_flags)
-               xfs_iunlock(ip, lock_flags);
-       IRELE(ip);
-}
-
-/*
- * This is called free all the memory associated with an inode.
- * It must free the inode itself and any buffers allocated for
- * if_extents/if_data and if_broot.  It must also free the lock
- * associated with the inode.
- *
- * Note: because we don't initialise everything on reallocation out
- * of the zone, we must ensure we nullify everything correctly before
- * freeing the structure.
- */
-void
-xfs_ireclaim(
-       struct xfs_inode        *ip)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_perag        *pag;
-       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
-
-       XFS_STATS_INC(xs_ig_reclaims);
-
-       /*
-        * Remove the inode from the per-AG radix tree.
-        *
-        * Because radix_tree_delete won't complain even if the item was never
-        * added to the tree assert that it's been there before to catch
-        * problems with the inode life time early on.
-        */
-       pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
-       write_lock(&pag->pag_ici_lock);
-       if (!radix_tree_delete(&pag->pag_ici_root, agino))
-               ASSERT(0);
-       write_unlock(&pag->pag_ici_lock);
-       xfs_perag_put(pag);
-
-       /*
-        * Here we do an (almost) spurious inode lock in order to coordinate
-        * with inode cache radix tree lookups.  This is because the lookup
-        * can reference the inodes in the cache without taking references.
-        *
-        * We make that OK here by ensuring that we wait until the inode is
-        * unlocked after the lookup before we go ahead and free it.  We get
-        * both the ilock and the iolock because the code may need to drop the
-        * ilock one but will still hold the iolock.
-        */
-       xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_qm_dqdetach(ip);
-       xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
-       xfs_inode_free(ip);
-}
-
 /*
  * This is a wrapper routine around the xfs_ilock() routine
  * used to centralize some grungy code.  It is used in places
index b76a829d7e200d4ead1b9e4406faf93f1e4093e0..68415cb4f23cab39861119c68838b1b099029df2 100644 (file)
 #include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -44,7 +41,6 @@
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_bmap.h"
-#include "xfs_rw.h"
 #include "xfs_error.h"
 #include "xfs_utils.h"
 #include "xfs_quota.h"
@@ -426,7 +422,7 @@ xfs_iformat(
        if (!XFS_DFORK_Q(dip))
                return 0;
        ASSERT(ip->i_afp == NULL);
-       ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
+       ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
        ip->i_afp->if_ext_max =
                XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
        switch (dip->di_aformat) {
@@ -509,7 +505,7 @@ xfs_iformat_local(
                ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
        else {
                real_size = roundup(size, 4);
-               ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
+               ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
        }
        ifp->if_bytes = size;
        ifp->if_real_bytes = real_size;
@@ -636,7 +632,7 @@ xfs_iformat_btree(
        }
 
        ifp->if_broot_bytes = size;
-       ifp->if_broot = kmem_alloc(size, KM_SLEEP);
+       ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
        ASSERT(ifp->if_broot != NULL);
        /*
         * Copy and convert from the on-disk structure
@@ -922,7 +918,6 @@ xfs_iread_extents(
        int             error;
        xfs_ifork_t     *ifp;
        xfs_extnum_t    nextents;
-       size_t          size;
 
        if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
                XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
@@ -930,7 +925,6 @@ xfs_iread_extents(
                return XFS_ERROR(EFSCORRUPTED);
        }
        nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
-       size = nextents * sizeof(xfs_bmbt_rec_t);
        ifp = XFS_IFORK_PTR(ip, whichfork);
 
        /*
@@ -1226,7 +1220,7 @@ xfs_isize_check(
                                       (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) -
                          map_first),
                         XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps,
-                        NULL, NULL))
+                        NULL))
            return;
        ASSERT(nimaps == 1);
        ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
@@ -1460,7 +1454,7 @@ xfs_itruncate_finish(
        ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
        ASSERT(ip->i_transp == *tp);
        ASSERT(ip->i_itemp != NULL);
-       ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD);
+       ASSERT(ip->i_itemp->ili_lock_flags == 0);
 
 
        ntp = *tp;
@@ -1589,11 +1583,10 @@ xfs_itruncate_finish(
                xfs_bmap_init(&free_list, &first_block);
                error = xfs_bunmapi(ntp, ip,
                                    first_unmap_block, unmap_len,
-                                   xfs_bmapi_aflag(fork) |
-                                     (sync ? 0 : XFS_BMAPI_ASYNC),
+                                   xfs_bmapi_aflag(fork),
                                    XFS_ITRUNC_MAX_EXTENTS,
                                    &first_block, &free_list,
-                                   NULL, &done);
+                                   &done);
                if (error) {
                        /*
                         * If the bunmapi call encounters an error,
@@ -1612,12 +1605,8 @@ xfs_itruncate_finish(
                 */
                error = xfs_bmap_finish(tp, &free_list, &committed);
                ntp = *tp;
-               if (committed) {
-                       /* link the inode into the next xact in the chain */
-                       xfs_trans_ijoin(ntp, ip,
-                                       XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-                       xfs_trans_ihold(ntp, ip);
-               }
+               if (committed)
+                       xfs_trans_ijoin(ntp, ip);
 
                if (error) {
                        /*
@@ -1646,9 +1635,7 @@ xfs_itruncate_finish(
                error = xfs_trans_commit(*tp, 0);
                *tp = ntp;
 
-               /* link the inode into the next transaction in the chain */
-               xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-               xfs_trans_ihold(ntp, ip);
+               xfs_trans_ijoin(ntp, ip);
 
                if (error)
                        return error;
@@ -1985,7 +1972,7 @@ xfs_ifree_cluster(
                        if (lip->li_type == XFS_LI_INODE) {
                                iip = (xfs_inode_log_item_t *)lip;
                                ASSERT(iip->ili_logged == 1);
-                               lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done;
+                               lip->li_cb = xfs_istale_done;
                                xfs_trans_ail_copy_lsn(mp->m_ail,
                                                        &iip->ili_flush_lsn,
                                                        &iip->ili_item.li_lsn);
@@ -2055,9 +2042,8 @@ xfs_ifree_cluster(
                        xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
                                                &iip->ili_item.li_lsn);
 
-                       xfs_buf_attach_iodone(bp,
-                               (void(*)(xfs_buf_t*,xfs_log_item_t*))
-                               xfs_istale_done, (xfs_log_item_t *)iip);
+                       xfs_buf_attach_iodone(bp, xfs_istale_done,
+                                                 &iip->ili_item);
 
                        if (ip != free_ip)
                                xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -2203,7 +2189,7 @@ xfs_iroot_realloc(
                 */
                if (ifp->if_broot_bytes == 0) {
                        new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff);
-                       ifp->if_broot = kmem_alloc(new_size, KM_SLEEP);
+                       ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
                        ifp->if_broot_bytes = (int)new_size;
                        return;
                }
@@ -2219,7 +2205,7 @@ xfs_iroot_realloc(
                new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
                ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
                                (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */
-                               KM_SLEEP);
+                               KM_SLEEP | KM_NOFS);
                op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
                                                     ifp->if_broot_bytes);
                np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
@@ -2245,7 +2231,7 @@ xfs_iroot_realloc(
        else
                new_size = 0;
        if (new_size > 0) {
-               new_broot = kmem_alloc(new_size, KM_SLEEP);
+               new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
                /*
                 * First copy over the btree block header.
                 */
@@ -2349,7 +2335,8 @@ xfs_idata_realloc(
                real_size = roundup(new_size, 4);
                if (ifp->if_u1.if_data == NULL) {
                        ASSERT(ifp->if_real_bytes == 0);
-                       ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
+                       ifp->if_u1.if_data = kmem_alloc(real_size,
+                                                       KM_SLEEP | KM_NOFS);
                } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
                        /*
                         * Only do the realloc if the underlying size
@@ -2360,11 +2347,12 @@ xfs_idata_realloc(
                                        kmem_realloc(ifp->if_u1.if_data,
                                                        real_size,
                                                        ifp->if_real_bytes,
-                                                       KM_SLEEP);
+                                                       KM_SLEEP | KM_NOFS);
                        }
                } else {
                        ASSERT(ifp->if_real_bytes == 0);
-                       ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
+                       ifp->if_u1.if_data = kmem_alloc(real_size,
+                                                       KM_SLEEP | KM_NOFS);
                        memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
                                ifp->if_bytes);
                }
@@ -2731,7 +2719,6 @@ cluster_corrupt_out:
                 * mark it as stale and brelse.
                 */
                if (XFS_BUF_IODONE_FUNC(bp)) {
-                       XFS_BUF_CLR_BDSTRAT_FUNC(bp);
                        XFS_BUF_UNDONE(bp);
                        XFS_BUF_STALE(bp);
                        XFS_BUF_ERROR(bp,EIO);
@@ -3069,8 +3056,7 @@ xfs_iflush_int(
                 * and unlock the inode's flush lock when the inode is
                 * completely written to disk.
                 */
-               xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*))
-                                     xfs_iflush_done, (xfs_log_item_t *)iip);
+               xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item);
 
                ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
                ASSERT(XFS_BUF_IODONE_FUNC(bp) != NULL);
@@ -3514,13 +3500,11 @@ xfs_iext_remove_indirect(
        xfs_extnum_t    ext_diff;       /* extents to remove in current list */
        xfs_extnum_t    nex1;           /* number of extents before idx */
        xfs_extnum_t    nex2;           /* extents after idx + count */
-       int             nlists;         /* entries in indirection array */
        int             page_idx = idx; /* index in target extent list */
 
        ASSERT(ifp->if_flags & XFS_IFEXTIREC);
        erp = xfs_iext_idx_to_irec(ifp,  &page_idx, &erp_idx, 0);
        ASSERT(erp != NULL);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
        nex1 = page_idx;
        ext_cnt = count;
        while (ext_cnt) {
index 78550df13cd664ee4811447f836e9d0f8dc31405..0898c5417d12b53476594d5cfdfaee665de56533 100644 (file)
@@ -443,8 +443,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
  */
 int            xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
                         uint, uint, xfs_inode_t **);
-void           xfs_iput(xfs_inode_t *, uint);
-void           xfs_iput_new(xfs_inode_t *, uint);
 void           xfs_ilock(xfs_inode_t *, uint);
 int            xfs_ilock_nowait(xfs_inode_t *, uint);
 void           xfs_iunlock(xfs_inode_t *, uint);
@@ -452,7 +450,7 @@ void                xfs_ilock_demote(xfs_inode_t *, uint);
 int            xfs_isilocked(xfs_inode_t *, uint);
 uint           xfs_ilock_map_shared(xfs_inode_t *);
 void           xfs_iunlock_map_shared(xfs_inode_t *, uint);
-void           xfs_ireclaim(xfs_inode_t *);
+void           xfs_inode_free(struct xfs_inode *ip);
 
 /*
  * xfs_inode.c prototypes.
index cf8249a600047b6d7dac03c7c11a4986020ce227..fe00777e2796317146ce1e20142cc7f4e3679635 100644 (file)
 #include "xfs_log.h"
 #include "xfs_inum.h"
 #include "xfs_trans.h"
-#include "xfs_buf_item.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
-#include "xfs_rw.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
 
 
 kmem_zone_t    *xfs_ili_zone;          /* inode log item zone */
 
+static inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_inode_log_item, ili_item);
+}
+
+
 /*
  * This returns the number of iovecs needed to log the given inode item.
  *
@@ -55,13 +51,11 @@ kmem_zone_t *xfs_ili_zone;          /* inode log item zone */
  */
 STATIC uint
 xfs_inode_item_size(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip)
 {
-       uint            nvecs;
-       xfs_inode_t     *ip;
-
-       ip = iip->ili_inode;
-       nvecs = 2;
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
+       uint                    nvecs = 2;
 
        /*
         * Only log the data/extents/b-tree root if there is something
@@ -212,21 +206,17 @@ xfs_inode_item_size(
  */
 STATIC void
 xfs_inode_item_format(
-       xfs_inode_log_item_t    *iip,
-       xfs_log_iovec_t         *log_vector)
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *vecp)
 {
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
        uint                    nvecs;
-       xfs_log_iovec_t         *vecp;
-       xfs_inode_t             *ip;
        size_t                  data_bytes;
        xfs_bmbt_rec_t          *ext_buffer;
-       int                     nrecs;
        xfs_mount_t             *mp;
 
-       ip = iip->ili_inode;
-       vecp = log_vector;
-
-       vecp->i_addr = (xfs_caddr_t)&iip->ili_format;
+       vecp->i_addr = &iip->ili_format;
        vecp->i_len  = sizeof(xfs_inode_log_format_t);
        vecp->i_type = XLOG_REG_TYPE_IFORMAT;
        vecp++;
@@ -277,7 +267,7 @@ xfs_inode_item_format(
         */
        xfs_synchronize_times(ip);
 
-       vecp->i_addr = (xfs_caddr_t)&ip->i_d;
+       vecp->i_addr = &ip->i_d;
        vecp->i_len  = sizeof(struct xfs_icdinode);
        vecp->i_type = XLOG_REG_TYPE_ICORE;
        vecp++;
@@ -323,18 +313,17 @@ xfs_inode_item_format(
                        ASSERT(ip->i_df.if_u1.if_extents != NULL);
                        ASSERT(ip->i_d.di_nextents > 0);
                        ASSERT(iip->ili_extents_buf == NULL);
-                       nrecs = ip->i_df.if_bytes /
-                               (uint)sizeof(xfs_bmbt_rec_t);
-                       ASSERT(nrecs > 0);
+                       ASSERT((ip->i_df.if_bytes /
+                               (uint)sizeof(xfs_bmbt_rec_t)) > 0);
 #ifdef XFS_NATIVE_HOST
-                       if (nrecs == ip->i_d.di_nextents) {
+                       if (ip->i_d.di_nextents == ip->i_df.if_bytes /
+                                               (uint)sizeof(xfs_bmbt_rec_t)) {
                                /*
                                 * There are no delayed allocation
                                 * extents, so just point to the
                                 * real extents array.
                                 */
-                               vecp->i_addr =
-                                       (char *)(ip->i_df.if_u1.if_extents);
+                               vecp->i_addr = ip->i_df.if_u1.if_extents;
                                vecp->i_len = ip->i_df.if_bytes;
                                vecp->i_type = XLOG_REG_TYPE_IEXT;
                        } else
@@ -352,7 +341,7 @@ xfs_inode_item_format(
                                ext_buffer = kmem_alloc(ip->i_df.if_bytes,
                                        KM_SLEEP);
                                iip->ili_extents_buf = ext_buffer;
-                               vecp->i_addr = (xfs_caddr_t)ext_buffer;
+                               vecp->i_addr = ext_buffer;
                                vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
                                                XFS_DATA_FORK);
                                vecp->i_type = XLOG_REG_TYPE_IEXT;
@@ -371,7 +360,7 @@ xfs_inode_item_format(
                if (iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) {
                        ASSERT(ip->i_df.if_broot_bytes > 0);
                        ASSERT(ip->i_df.if_broot != NULL);
-                       vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot;
+                       vecp->i_addr = ip->i_df.if_broot;
                        vecp->i_len = ip->i_df.if_broot_bytes;
                        vecp->i_type = XLOG_REG_TYPE_IBROOT;
                        vecp++;
@@ -389,7 +378,7 @@ xfs_inode_item_format(
                        ASSERT(ip->i_df.if_u1.if_data != NULL);
                        ASSERT(ip->i_d.di_size > 0);
 
-                       vecp->i_addr = (xfs_caddr_t)ip->i_df.if_u1.if_data;
+                       vecp->i_addr = ip->i_df.if_u1.if_data;
                        /*
                         * Round i_bytes up to a word boundary.
                         * The underlying memory is guaranteed to
@@ -437,7 +426,7 @@ xfs_inode_item_format(
         * Assert that no attribute-related log flags are set.
         */
        if (!XFS_IFORK_Q(ip)) {
-               ASSERT(nvecs == iip->ili_item.li_desc->lid_size);
+               ASSERT(nvecs == lip->li_desc->lid_size);
                iip->ili_format.ilf_size = nvecs;
                ASSERT(!(iip->ili_format.ilf_fields &
                         (XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT)));
@@ -449,21 +438,21 @@ xfs_inode_item_format(
                ASSERT(!(iip->ili_format.ilf_fields &
                         (XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
                if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
-                       ASSERT(ip->i_afp->if_bytes > 0);
-                       ASSERT(ip->i_afp->if_u1.if_extents != NULL);
-                       ASSERT(ip->i_d.di_anextents > 0);
 #ifdef DEBUG
-                       nrecs = ip->i_afp->if_bytes /
+                       int nrecs = ip->i_afp->if_bytes /
                                (uint)sizeof(xfs_bmbt_rec_t);
-#endif
                        ASSERT(nrecs > 0);
                        ASSERT(nrecs == ip->i_d.di_anextents);
+                       ASSERT(ip->i_afp->if_bytes > 0);
+                       ASSERT(ip->i_afp->if_u1.if_extents != NULL);
+                       ASSERT(ip->i_d.di_anextents > 0);
+#endif
 #ifdef XFS_NATIVE_HOST
                        /*
                         * There are not delayed allocation extents
                         * for attributes, so just point at the array.
                         */
-                       vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents);
+                       vecp->i_addr = ip->i_afp->if_u1.if_extents;
                        vecp->i_len = ip->i_afp->if_bytes;
 #else
                        ASSERT(iip->ili_aextents_buf == NULL);
@@ -473,7 +462,7 @@ xfs_inode_item_format(
                        ext_buffer = kmem_alloc(ip->i_afp->if_bytes,
                                KM_SLEEP);
                        iip->ili_aextents_buf = ext_buffer;
-                       vecp->i_addr = (xfs_caddr_t)ext_buffer;
+                       vecp->i_addr = ext_buffer;
                        vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
                                        XFS_ATTR_FORK);
 #endif
@@ -490,7 +479,7 @@ xfs_inode_item_format(
                if (iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) {
                        ASSERT(ip->i_afp->if_broot_bytes > 0);
                        ASSERT(ip->i_afp->if_broot != NULL);
-                       vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot;
+                       vecp->i_addr = ip->i_afp->if_broot;
                        vecp->i_len = ip->i_afp->if_broot_bytes;
                        vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT;
                        vecp++;
@@ -506,7 +495,7 @@ xfs_inode_item_format(
                        ASSERT(ip->i_afp->if_bytes > 0);
                        ASSERT(ip->i_afp->if_u1.if_data != NULL);
 
-                       vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_u1.if_data;
+                       vecp->i_addr = ip->i_afp->if_u1.if_data;
                        /*
                         * Round i_bytes up to a word boundary.
                         * The underlying memory is guaranteed to
@@ -528,7 +517,7 @@ xfs_inode_item_format(
                break;
        }
 
-       ASSERT(nvecs == iip->ili_item.li_desc->lid_size);
+       ASSERT(nvecs == lip->li_desc->lid_size);
        iip->ili_format.ilf_size = nvecs;
 }
 
@@ -539,12 +528,14 @@ xfs_inode_item_format(
  */
 STATIC void
 xfs_inode_item_pin(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip)
 {
-       ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
+       struct xfs_inode        *ip = INODE_ITEM(lip)->ili_inode;
+
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-       trace_xfs_inode_pin(iip->ili_inode, _RET_IP_);
-       atomic_inc(&iip->ili_inode->i_pincount);
+       trace_xfs_inode_pin(ip, _RET_IP_);
+       atomic_inc(&ip->i_pincount);
 }
 
 
@@ -554,12 +545,12 @@ xfs_inode_item_pin(
  *
  * Also wake up anyone in xfs_iunpin_wait() if the count goes to 0.
  */
-/* ARGSUSED */
 STATIC void
 xfs_inode_item_unpin(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip,
+       int                     remove)
 {
-       struct xfs_inode        *ip = iip->ili_inode;
+       struct xfs_inode        *ip = INODE_ITEM(lip)->ili_inode;
 
        trace_xfs_inode_unpin(ip, _RET_IP_);
        ASSERT(atomic_read(&ip->i_pincount) > 0);
@@ -567,15 +558,6 @@ xfs_inode_item_unpin(
                wake_up(&ip->i_ipin_wait);
 }
 
-/* ARGSUSED */
-STATIC void
-xfs_inode_item_unpin_remove(
-       xfs_inode_log_item_t    *iip,
-       xfs_trans_t             *tp)
-{
-       xfs_inode_item_unpin(iip);
-}
-
 /*
  * This is called to attempt to lock the inode associated with this
  * inode log item, in preparation for the push routine which does the actual
@@ -591,19 +573,16 @@ xfs_inode_item_unpin_remove(
  */
 STATIC uint
 xfs_inode_item_trylock(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip)
 {
-       register xfs_inode_t    *ip;
-
-       ip = iip->ili_inode;
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
 
-       if (xfs_ipincount(ip) > 0) {
+       if (xfs_ipincount(ip) > 0)
                return XFS_ITEM_PINNED;
-       }
 
-       if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
+       if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
                return XFS_ITEM_LOCKED;
-       }
 
        if (!xfs_iflock_nowait(ip)) {
                /*
@@ -629,7 +608,7 @@ xfs_inode_item_trylock(
        if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
                ASSERT(iip->ili_format.ilf_fields != 0);
                ASSERT(iip->ili_logged == 0);
-               ASSERT(iip->ili_item.li_flags & XFS_LI_IN_AIL);
+               ASSERT(lip->li_flags & XFS_LI_IN_AIL);
        }
 #endif
        return XFS_ITEM_SUCCESS;
@@ -643,26 +622,18 @@ xfs_inode_item_trylock(
  */
 STATIC void
 xfs_inode_item_unlock(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip)
 {
-       uint            hold;
-       uint            iolocked;
-       uint            lock_flags;
-       xfs_inode_t     *ip;
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
+       unsigned short          lock_flags;
 
-       ASSERT(iip != NULL);
        ASSERT(iip->ili_inode->i_itemp != NULL);
        ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
-       ASSERT((!(iip->ili_inode->i_itemp->ili_flags &
-                 XFS_ILI_IOLOCKED_EXCL)) ||
-              xfs_isilocked(iip->ili_inode, XFS_IOLOCK_EXCL));
-       ASSERT((!(iip->ili_inode->i_itemp->ili_flags &
-                 XFS_ILI_IOLOCKED_SHARED)) ||
-              xfs_isilocked(iip->ili_inode, XFS_IOLOCK_SHARED));
+
        /*
         * Clear the transaction pointer in the inode.
         */
-       ip = iip->ili_inode;
        ip->i_transp = NULL;
 
        /*
@@ -686,34 +657,11 @@ xfs_inode_item_unlock(
                iip->ili_aextents_buf = NULL;
        }
 
-       /*
-        * Figure out if we should unlock the inode or not.
-        */
-       hold = iip->ili_flags & XFS_ILI_HOLD;
-
-       /*
-        * Before clearing out the flags, remember whether we
-        * are holding the inode's IO lock.
-        */
-       iolocked = iip->ili_flags & XFS_ILI_IOLOCKED_ANY;
-
-       /*
-        * Clear out the fields of the inode log item particular
-        * to the current transaction.
-        */
-       iip->ili_flags = 0;
-
-       /*
-        * Unlock the inode if XFS_ILI_HOLD was not set.
-        */
-       if (!hold) {
-               lock_flags = XFS_ILOCK_EXCL;
-               if (iolocked & XFS_ILI_IOLOCKED_EXCL) {
-                       lock_flags |= XFS_IOLOCK_EXCL;
-               } else if (iolocked & XFS_ILI_IOLOCKED_SHARED) {
-                       lock_flags |= XFS_IOLOCK_SHARED;
-               }
-               xfs_iput(iip->ili_inode, lock_flags);
+       lock_flags = iip->ili_lock_flags;
+       iip->ili_lock_flags = 0;
+       if (lock_flags) {
+               xfs_iunlock(iip->ili_inode, lock_flags);
+               IRELE(iip->ili_inode);
        }
 }
 
@@ -725,13 +673,12 @@ xfs_inode_item_unlock(
  * is the only one that matters.  Therefore, simply return the
  * given lsn.
  */
-/*ARGSUSED*/
 STATIC xfs_lsn_t
 xfs_inode_item_committed(
-       xfs_inode_log_item_t    *iip,
+       struct xfs_log_item     *lip,
        xfs_lsn_t               lsn)
 {
-       return (lsn);
+       return lsn;
 }
 
 /*
@@ -743,13 +690,12 @@ xfs_inode_item_committed(
  */
 STATIC void
 xfs_inode_item_pushbuf(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip)
 {
-       xfs_inode_t     *ip;
-       xfs_mount_t     *mp;
-       xfs_buf_t       *bp;
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
+       struct xfs_buf          *bp;
 
-       ip = iip->ili_inode;
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
 
        /*
@@ -757,14 +703,13 @@ xfs_inode_item_pushbuf(
         * inode was taken off the AIL. So, just get out.
         */
        if (completion_done(&ip->i_flush) ||
-           ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) {
+           !(lip->li_flags & XFS_LI_IN_AIL)) {
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
                return;
        }
 
-       mp = ip->i_mount;
-       bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno,
-                   iip->ili_format.ilf_len, XBF_TRYLOCK);
+       bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
+                       iip->ili_format.ilf_len, XBF_TRYLOCK);
 
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
        if (!bp)
@@ -772,10 +717,8 @@ xfs_inode_item_pushbuf(
        if (XFS_BUF_ISDELAYWRITE(bp))
                xfs_buf_delwri_promote(bp);
        xfs_buf_relse(bp);
-       return;
 }
 
-
 /*
  * This is called to asynchronously write the inode associated with this
  * inode log item out to disk. The inode will already have been locked by
@@ -783,14 +726,14 @@ xfs_inode_item_pushbuf(
  */
 STATIC void
 xfs_inode_item_push(
-       xfs_inode_log_item_t    *iip)
+       struct xfs_log_item     *lip)
 {
-       xfs_inode_t     *ip;
-
-       ip = iip->ili_inode;
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
        ASSERT(!completion_done(&ip->i_flush));
+
        /*
         * Since we were able to lock the inode's flush lock and
         * we found it on the AIL, the inode must be dirty.  This
@@ -813,43 +756,34 @@ xfs_inode_item_push(
         */
        (void) xfs_iflush(ip, 0);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       return;
 }
 
 /*
  * XXX rcc - this one really has to do something.  Probably needs
  * to stamp in a new field in the incore inode.
  */
-/* ARGSUSED */
 STATIC void
 xfs_inode_item_committing(
-       xfs_inode_log_item_t    *iip,
+       struct xfs_log_item     *lip,
        xfs_lsn_t               lsn)
 {
-       iip->ili_last_lsn = lsn;
-       return;
+       INODE_ITEM(lip)->ili_last_lsn = lsn;
 }
 
 /*
  * This is the ops vector shared by all buf log items.
  */
 static struct xfs_item_ops xfs_inode_item_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_inode_item_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_inode_item_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_inode_item_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*))xfs_inode_item_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
-                                       xfs_inode_item_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_inode_item_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_inode_item_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_inode_item_push,
-       .iop_pushbuf    = (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_inode_item_committing
+       .iop_size       = xfs_inode_item_size,
+       .iop_format     = xfs_inode_item_format,
+       .iop_pin        = xfs_inode_item_pin,
+       .iop_unpin      = xfs_inode_item_unpin,
+       .iop_trylock    = xfs_inode_item_trylock,
+       .iop_unlock     = xfs_inode_item_unlock,
+       .iop_committed  = xfs_inode_item_committed,
+       .iop_push       = xfs_inode_item_push,
+       .iop_pushbuf    = xfs_inode_item_pushbuf,
+       .iop_committing = xfs_inode_item_committing
 };
 
 
@@ -858,10 +792,10 @@ static struct xfs_item_ops xfs_inode_item_ops = {
  */
 void
 xfs_inode_item_init(
-       xfs_inode_t     *ip,
-       xfs_mount_t     *mp)
+       struct xfs_inode        *ip,
+       struct xfs_mount        *mp)
 {
-       xfs_inode_log_item_t    *iip;
+       struct xfs_inode_log_item *iip;
 
        ASSERT(ip->i_itemp == NULL);
        iip = ip->i_itemp = kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP);
@@ -899,14 +833,14 @@ xfs_inode_item_destroy(
  * from the AIL if it has not been re-logged, and unlocking the inode's
  * flush lock.
  */
-/*ARGSUSED*/
 void
 xfs_iflush_done(
-       xfs_buf_t               *bp,
-       xfs_inode_log_item_t    *iip)
+       struct xfs_buf          *bp,
+       struct xfs_log_item     *lip)
 {
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
        xfs_inode_t             *ip = iip->ili_inode;
-       struct xfs_ail          *ailp = iip->ili_item.li_ailp;
+       struct xfs_ail          *ailp = lip->li_ailp;
 
        /*
         * We only want to pull the item from the AIL if it is
@@ -917,12 +851,11 @@ xfs_iflush_done(
         * the lock since it's cheaper, and then we recheck while
         * holding the lock before removing the inode from the AIL.
         */
-       if (iip->ili_logged &&
-           (iip->ili_item.li_lsn == iip->ili_flush_lsn)) {
+       if (iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) {
                spin_lock(&ailp->xa_lock);
-               if (iip->ili_item.li_lsn == iip->ili_flush_lsn) {
+               if (lip->li_lsn == iip->ili_flush_lsn) {
                        /* xfs_trans_ail_delete() drops the AIL lock. */
-                       xfs_trans_ail_delete(ailp, (xfs_log_item_t*)iip);
+                       xfs_trans_ail_delete(ailp, lip);
                } else {
                        spin_unlock(&ailp->xa_lock);
                }
@@ -940,8 +873,6 @@ xfs_iflush_done(
         * Release the inode's flush lock since we're done with it.
         */
        xfs_ifunlock(ip);
-
-       return;
 }
 
 /*
@@ -957,10 +888,8 @@ xfs_iflush_abort(
        xfs_inode_t             *ip)
 {
        xfs_inode_log_item_t    *iip = ip->i_itemp;
-       xfs_mount_t             *mp;
 
        iip = ip->i_itemp;
-       mp = ip->i_mount;
        if (iip) {
                struct xfs_ail  *ailp = iip->ili_item.li_ailp;
                if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
@@ -991,10 +920,10 @@ xfs_iflush_abort(
 
 void
 xfs_istale_done(
-       xfs_buf_t               *bp,
-       xfs_inode_log_item_t    *iip)
+       struct xfs_buf          *bp,
+       struct xfs_log_item     *lip)
 {
-       xfs_iflush_abort(iip->ili_inode);
+       xfs_iflush_abort(INODE_ITEM(lip)->ili_inode);
 }
 
 /*
@@ -1007,9 +936,8 @@ xfs_inode_item_format_convert(
        xfs_inode_log_format_t  *in_f)
 {
        if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) {
-               xfs_inode_log_format_32_t *in_f32;
+               xfs_inode_log_format_32_t *in_f32 = buf->i_addr;
 
-               in_f32 = (xfs_inode_log_format_32_t *)buf->i_addr;
                in_f->ilf_type = in_f32->ilf_type;
                in_f->ilf_size = in_f32->ilf_size;
                in_f->ilf_fields = in_f32->ilf_fields;
@@ -1025,9 +953,8 @@ xfs_inode_item_format_convert(
                in_f->ilf_boffset = in_f32->ilf_boffset;
                return 0;
        } else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){
-               xfs_inode_log_format_64_t *in_f64;
+               xfs_inode_log_format_64_t *in_f64 = buf->i_addr;
 
-               in_f64 = (xfs_inode_log_format_64_t *)buf->i_addr;
                in_f->ilf_type = in_f64->ilf_type;
                in_f->ilf_size = in_f64->ilf_size;
                in_f->ilf_fields = in_f64->ilf_fields;
index 9a467958ecdd4706e22c5f16faf212b7fda7f3ad..d3dee61e6d91fde1671157b3ee2deeee8df49fcd 100644 (file)
@@ -103,12 +103,6 @@ typedef struct xfs_inode_log_format_64 {
                                 XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
                                 XFS_ILOG_ABROOT)
 
-#define        XFS_ILI_HOLD            0x1
-#define        XFS_ILI_IOLOCKED_EXCL   0x2
-#define        XFS_ILI_IOLOCKED_SHARED 0x4
-
-#define        XFS_ILI_IOLOCKED_ANY   (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED)
-
 static inline int xfs_ilog_fbroot(int w)
 {
        return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
@@ -137,7 +131,7 @@ typedef struct xfs_inode_log_item {
        struct xfs_inode        *ili_inode;        /* inode ptr */
        xfs_lsn_t               ili_flush_lsn;     /* lsn at last flush */
        xfs_lsn_t               ili_last_lsn;      /* lsn at last transaction */
-       unsigned short          ili_flags;         /* misc flags */
+       unsigned short          ili_lock_flags;    /* lock flags */
        unsigned short          ili_logged;        /* flushed logged data */
        unsigned int            ili_last_fields;   /* fields when flushed */
        struct xfs_bmbt_rec     *ili_extents_buf;  /* array of logged
@@ -161,8 +155,8 @@ static inline int xfs_inode_clean(xfs_inode_t *ip)
 
 extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
 extern void xfs_inode_item_destroy(struct xfs_inode *);
-extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *);
-extern void xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *);
+extern void xfs_iflush_done(struct xfs_buf *, struct xfs_log_item *);
+extern void xfs_istale_done(struct xfs_buf *, struct xfs_log_item *);
 extern void xfs_iflush_abort(struct xfs_inode *);
 extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
                                         xfs_inode_log_format_t *);
index ef14943829dabc38aa0f4f7d667ce0de6f9f2d05..20576146369f86fffa9f7f40dfe4d33f2b363fb5 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
-#include "xfs_dmapi.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_ialloc.h"
 #include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
@@ -123,7 +118,7 @@ xfs_iomap(
        error = xfs_bmapi(NULL, ip, offset_fsb,
                        (xfs_filblks_t)(end_fsb - offset_fsb),
                        bmapi_flags,  NULL, 0, imap,
-                       nimaps, NULL, NULL);
+                       nimaps, NULL);
 
        if (error)
                goto out;
@@ -138,7 +133,7 @@ xfs_iomap(
                        break;
                }
 
-               if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) {
+               if (flags & BMAPI_DIRECT) {
                        error = xfs_iomap_write_direct(ip, offset, count, flags,
                                                       imap, nimaps);
                } else {
@@ -247,7 +242,7 @@ xfs_iomap_write_direct(
        xfs_off_t       offset,
        size_t          count,
        int             flags,
-       xfs_bmbt_irec_t *ret_imap,
+       xfs_bmbt_irec_t *imap,
        int             *nmaps)
 {
        xfs_mount_t     *mp = ip->i_mount;
@@ -261,7 +256,6 @@ xfs_iomap_write_direct(
        int             quota_flag;
        int             rt;
        xfs_trans_t     *tp;
-       xfs_bmbt_irec_t imap;
        xfs_bmap_free_t free_list;
        uint            qblocks, resblks, resrtextents;
        int             committed;
@@ -285,10 +279,10 @@ xfs_iomap_write_direct(
                if (error)
                        goto error_out;
        } else {
-               if (*nmaps && (ret_imap->br_startblock == HOLESTARTBLOCK))
+               if (*nmaps && (imap->br_startblock == HOLESTARTBLOCK))
                        last_fsb = MIN(last_fsb, (xfs_fileoff_t)
-                                       ret_imap->br_blockcount +
-                                       ret_imap->br_startoff);
+                                       imap->br_blockcount +
+                                       imap->br_startoff);
        }
        count_fsb = last_fsb - offset_fsb;
        ASSERT(count_fsb > 0);
@@ -334,20 +328,22 @@ xfs_iomap_write_direct(
        if (error)
                goto error1;
 
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
 
        bmapi_flag = XFS_BMAPI_WRITE;
        if ((flags & BMAPI_DIRECT) && (offset < ip->i_size || extsz))
                bmapi_flag |= XFS_BMAPI_PREALLOC;
 
        /*
-        * Issue the xfs_bmapi() call to allocate the blocks
+        * Issue the xfs_bmapi() call to allocate the blocks.
+        *
+        * From this point onwards we overwrite the imap pointer that the
+        * caller gave to us.
         */
        xfs_bmap_init(&free_list, &firstfsb);
        nimaps = 1;
        error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, bmapi_flag,
-               &firstfsb, 0, &imap, &nimaps, &free_list, NULL);
+               &firstfsb, 0, imap, &nimaps, &free_list);
        if (error)
                goto error0;
 
@@ -369,12 +365,11 @@ xfs_iomap_write_direct(
                goto error_out;
        }
 
-       if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) {
-               error = xfs_cmn_err_fsblock_zero(ip, &imap);
+       if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) {
+               error = xfs_cmn_err_fsblock_zero(ip, imap);
                goto error_out;
        }
 
-       *ret_imap = imap;
        *nmaps = 1;
        return 0;
 
@@ -425,7 +420,7 @@ xfs_iomap_eof_want_preallocate(
                imaps = nimaps;
                firstblock = NULLFSBLOCK;
                error = xfs_bmapi(NULL, ip, start_fsb, count_fsb, 0,
-                                 &firstblock, 0, imap, &imaps, NULL, NULL);
+                                 &firstblock, 0, imap, &imaps, NULL);
                if (error)
                        return error;
                for (n = 0; n < imaps; n++) {
@@ -500,7 +495,7 @@ retry:
                          (xfs_filblks_t)(last_fsb - offset_fsb),
                          XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
                          XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
-                         &nimaps, NULL, NULL);
+                         &nimaps, NULL);
        if (error && (error != ENOSPC))
                return XFS_ERROR(error);
 
@@ -548,7 +543,7 @@ xfs_iomap_write_allocate(
        xfs_inode_t     *ip,
        xfs_off_t       offset,
        size_t          count,
-       xfs_bmbt_irec_t *map,
+       xfs_bmbt_irec_t *imap,
        int             *retmap)
 {
        xfs_mount_t     *mp = ip->i_mount;
@@ -557,7 +552,6 @@ xfs_iomap_write_allocate(
        xfs_fsblock_t   first_block;
        xfs_bmap_free_t free_list;
        xfs_filblks_t   count_fsb;
-       xfs_bmbt_irec_t imap;
        xfs_trans_t     *tp;
        int             nimaps, committed;
        int             error = 0;
@@ -573,8 +567,8 @@ xfs_iomap_write_allocate(
                return XFS_ERROR(error);
 
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       count_fsb = map->br_blockcount;
-       map_start_fsb = map->br_startoff;
+       count_fsb = imap->br_blockcount;
+       map_start_fsb = imap->br_startoff;
 
        XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
 
@@ -602,8 +596,7 @@ xfs_iomap_write_allocate(
                                return XFS_ERROR(error);
                        }
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
-                       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-                       xfs_trans_ihold(tp, ip);
+                       xfs_trans_ijoin(tp, ip);
 
                        xfs_bmap_init(&free_list, &first_block);
 
@@ -654,10 +647,15 @@ xfs_iomap_write_allocate(
                                }
                        }
 
-                       /* Go get the actual blocks */
+                       /*
+                        * Go get the actual blocks.
+                        *
+                        * From this point onwards we overwrite the imap
+                        * pointer that the caller gave to us.
+                        */
                        error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb,
                                        XFS_BMAPI_WRITE, &first_block, 1,
-                                       &imap, &nimaps, &free_list, NULL);
+                                       imap, &nimaps, &free_list);
                        if (error)
                                goto trans_cancel;
 
@@ -676,13 +674,12 @@ xfs_iomap_write_allocate(
                 * See if we were able to allocate an extent that
                 * 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);
+               if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip)))
+                       return xfs_cmn_err_fsblock_zero(ip, imap);
 
-               if ((offset_fsb >= imap.br_startoff) &&
-                   (offset_fsb < (imap.br_startoff +
-                                  imap.br_blockcount))) {
-                       *map = imap;
+               if ((offset_fsb >= imap->br_startoff) &&
+                   (offset_fsb < (imap->br_startoff +
+                                  imap->br_blockcount))) {
                        *retmap = 1;
                        XFS_STATS_INC(xs_xstrat_quick);
                        return 0;
@@ -692,8 +689,8 @@ xfs_iomap_write_allocate(
                 * So far we have not mapped the requested part of the
                 * file, just surrounding data, try again.
                 */
-               count_fsb -= imap.br_blockcount;
-               map_start_fsb = imap.br_startoff + imap.br_blockcount;
+               count_fsb -= imap->br_blockcount;
+               map_start_fsb = imap->br_startoff + imap->br_blockcount;
        }
 
 trans_cancel:
@@ -766,8 +763,7 @@ xfs_iomap_write_unwritten(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * Modify the unwritten extent state of the buffer.
@@ -776,7 +772,7 @@ xfs_iomap_write_unwritten(
                nimaps = 1;
                error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
                                  XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb,
-                                 1, &imap, &nimaps, &free_list, NULL);
+                                 1, &imap, &nimaps, &free_list);
                if (error)
                        goto error_on_bmapi_transaction;
 
index 81ac4afd45b3300c80261fb11e1d61dfceea007e..7748a430f50d229d82d66771ee759927dc41d983 100644 (file)
 #ifndef __XFS_IOMAP_H__
 #define __XFS_IOMAP_H__
 
-typedef enum {
-       /* base extent manipulation calls */
-       BMAPI_READ = (1 << 0),          /* read extents */
-       BMAPI_WRITE = (1 << 1),         /* create extents */
-       BMAPI_ALLOCATE = (1 << 2),      /* delayed allocate to real extents */
-       /* modifiers */
-       BMAPI_IGNSTATE = (1 << 4),      /* ignore unwritten state on read */
-       BMAPI_DIRECT = (1 << 5),        /* direct instead of buffered write */
-       BMAPI_MMAP = (1 << 6),          /* allocate for mmap write */
-       BMAPI_TRYLOCK = (1 << 7),       /* non-blocking request */
-} bmapi_flags_t;
+/* base extent manipulation calls */
+#define BMAPI_READ     (1 << 0)        /* read extents */
+#define BMAPI_WRITE    (1 << 1)        /* create extents */
+#define BMAPI_ALLOCATE (1 << 2)        /* delayed allocate to real extents */
+
+/* modifiers */
+#define BMAPI_IGNSTATE (1 << 4)        /* ignore unwritten state on read */
+#define BMAPI_DIRECT   (1 << 5)        /* direct instead of buffered write */
+#define BMAPI_MMA      (1 << 6)        /* allocate for mmap write */
+#define BMAPI_TRYLOCK  (1 << 7)        /* non-blocking request */
 
 #define BMAPI_FLAGS \
        { BMAPI_READ,           "READ" }, \
@@ -36,7 +35,6 @@ typedef enum {
        { BMAPI_ALLOCATE,       "ALLOCATE" }, \
        { BMAPI_IGNSTATE,       "IGNSTATE" }, \
        { BMAPI_DIRECT,         "DIRECT" }, \
-       { BMAPI_MMAP,           "MMAP" }, \
        { BMAPI_TRYLOCK,        "TRYLOCK" }
 
 struct xfs_inode;
index 2b86f86105125c3869a641b68bc73b984ce69e79..7e3626e5925c4ada9ed16e4fa103bbefd0ef1734 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_ialloc.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
 #include "xfs_btree.h"
+#include "xfs_trace.h"
 
 STATIC int
 xfs_internal_inum(
@@ -143,7 +140,8 @@ xfs_bulkstat_one_int(
                buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;
                break;
        }
-       xfs_iput(ip, XFS_ILOCK_SHARED);
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       IRELE(ip);
 
        error = formatter(buffer, ubsize, ubused, buf);
 
index 5215abc8023aadf15014c8f475ed529508695e30..925d572bf0f405e9a94be11b74549c5f760b3ec4 100644 (file)
@@ -24,8 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_error.h"
 #include "xfs_log_priv.h"
@@ -35,8 +33,6 @@
 #include "xfs_ialloc_btree.h"
 #include "xfs_log_recover.h"
 #include "xfs_trans_priv.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_rw.h"
@@ -337,7 +333,6 @@ xfs_log_reserve(
        int                     retval = 0;
 
        ASSERT(client == XFS_TRANSACTION || client == XFS_LOG);
-       ASSERT((flags & XFS_LOG_NOSLEEP) == 0);
 
        if (XLOG_FORCED_SHUTDOWN(log))
                return XFS_ERROR(EIO);
@@ -552,7 +547,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
                                .magic = XLOG_UNMOUNT_TYPE,
                        };
                        struct xfs_log_iovec reg = {
-                               .i_addr = (void *)&magic,
+                               .i_addr = &magic,
                                .i_len = sizeof(magic),
                                .i_type = XLOG_REG_TYPE_UNMOUNT,
                        };
@@ -1047,7 +1042,6 @@ xlog_alloc_log(xfs_mount_t        *mp,
        xlog_in_core_t          *iclog, *prev_iclog=NULL;
        xfs_buf_t               *bp;
        int                     i;
-       int                     iclogsize;
        int                     error = ENOMEM;
        uint                    log2_size = 0;
 
@@ -1127,7 +1121,6 @@ xlog_alloc_log(xfs_mount_t        *mp,
         * with different amounts of memory.  See the definition of
         * xlog_in_core_t in xfs_log_priv.h for details.
         */
-       iclogsize = log->l_iclog_size;
        ASSERT(log->l_iclog_size >= 4096);
        for (i=0; i < log->l_iclog_bufs; i++) {
                *iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL);
@@ -1428,11 +1421,8 @@ xlog_sync(xlog_t         *log,
        XFS_BUF_BUSY(bp);
        XFS_BUF_ASYNC(bp);
        bp->b_flags |= XBF_LOG_BUFFER;
-       /*
-        * Do an ordered write for the log block.
-        * Its unnecessary to flush the first split block in the log wrap case.
-        */
-       if (!split && (log->l_mp->m_flags & XFS_MOUNT_BARRIER))
+
+       if (log->l_mp->m_flags & XFS_MOUNT_BARRIER)
                XFS_BUF_ORDERED(bp);
 
        ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
index 04c78e642cc83b237ed0c5d6258f82e0ccdcad26..916eb7db14d9a09ff541882bf12905d9fd5068ea 100644 (file)
@@ -55,14 +55,10 @@ static inline xfs_lsn_t     _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 /*
  * Flags to xfs_log_reserve()
  *
- *     XFS_LOG_SLEEP:   If space is not available, sleep (default)
- *     XFS_LOG_NOSLEEP: If space is not available, return error
  *     XFS_LOG_PERM_RESERV: Permanent reservation.  When writes are
  *             performed against this type of reservation, the reservation
  *             is not decreased.  Long running transactions should use this.
  */
-#define XFS_LOG_SLEEP          0x0
-#define XFS_LOG_NOSLEEP                0x1
 #define XFS_LOG_PERM_RESERV    0x2
 
 /*
@@ -104,7 +100,7 @@ static inline xfs_lsn_t     _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 #define XLOG_REG_TYPE_MAX              19
 
 typedef struct xfs_log_iovec {
-       xfs_caddr_t     i_addr;         /* beginning address of region */
+       void            *i_addr;        /* beginning address of region */
        int             i_len;          /* length in bytes of region */
        uint            i_type;         /* type of region */
 } xfs_log_iovec_t;
@@ -201,9 +197,4 @@ int xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
 bool   xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
 
 #endif
-
-
-extern int xlog_debug;         /* set to 1 to enable real log */
-
-
 #endif /* __XFS_LOG_H__ */
index bb17cc044bf37c994dbf877292ecaf36aa3842fb..31e4ea2d19acfc08f069813dffa367e6b2420973 100644 (file)
@@ -26,8 +26,6 @@
 #include "xfs_log_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_error.h"
 #include "xfs_alloc.h"
@@ -554,7 +552,7 @@ xlog_cil_push(
        thdr.th_type = XFS_TRANS_CHECKPOINT;
        thdr.th_tid = tic->t_tid;
        thdr.th_num_items = num_iovecs;
-       lhdr.i_addr = (xfs_caddr_t)&thdr;
+       lhdr.i_addr = &thdr;
        lhdr.i_len = sizeof(xfs_trans_header_t);
        lhdr.i_type = XLOG_REG_TYPE_TRANSHDR;
        tic->t_curr_res -= lhdr.i_len + sizeof(xlog_op_header_t);
index 9ac5cfab27b96da77ac033559229090a3c52490a..6f3f5fa37acf16cec91cf55eb36d0d7c1b20d0b2 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_error.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
@@ -1565,9 +1561,7 @@ xlog_recover_reorder_trans(
 
        list_splice_init(&trans->r_itemq, &sort_list);
        list_for_each_entry_safe(item, n, &sort_list, ri_list) {
-               xfs_buf_log_format_t    *buf_f;
-
-               buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr;
+               xfs_buf_log_format_t    *buf_f = item->ri_buf[0].i_addr;
 
                switch (ITEM_TYPE(item)) {
                case XFS_LI_BUF:
@@ -1892,9 +1886,8 @@ xlog_recover_do_inode_buffer(
                 * current di_next_unlinked field.  Extract its value
                 * and copy it to the buffer copy.
                 */
-               logged_nextp = (xfs_agino_t *)
-                              ((char *)(item->ri_buf[item_index].i_addr) +
-                               (next_unlinked_offset - reg_buf_offset));
+               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",
@@ -1973,8 +1966,7 @@ xlog_recover_do_reg_buffer(
                                        item->ri_buf[i].i_len, __func__);
                                goto next;
                        }
-                       error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
-                                              item->ri_buf[i].i_addr,
+                       error = xfs_qm_dqcheck(item->ri_buf[i].i_addr,
                                               -1, 0, XFS_QMOPT_DOWARN,
                                               "dquot_buf_recover");
                        if (error)
@@ -2187,7 +2179,7 @@ xlog_recover_do_buffer_trans(
        xlog_recover_item_t     *item,
        int                     pass)
 {
-       xfs_buf_log_format_t    *buf_f;
+       xfs_buf_log_format_t    *buf_f = item->ri_buf[0].i_addr;
        xfs_mount_t             *mp;
        xfs_buf_t               *bp;
        int                     error;
@@ -2197,8 +2189,6 @@ xlog_recover_do_buffer_trans(
        ushort                  flags;
        uint                    buf_flags;
 
-       buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr;
-
        if (pass == XLOG_RECOVER_PASS1) {
                /*
                 * In this pass we're only looking for buf items
@@ -2319,10 +2309,9 @@ xlog_recover_do_inode_trans(
        }
 
        if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) {
-               in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
+               in_f = item->ri_buf[0].i_addr;
        } else {
-               in_f = (xfs_inode_log_format_t *)kmem_alloc(
-                       sizeof(xfs_inode_log_format_t), KM_SLEEP);
+               in_f = kmem_alloc(sizeof(xfs_inode_log_format_t), KM_SLEEP);
                need_free = 1;
                error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
                if (error)
@@ -2370,7 +2359,7 @@ xlog_recover_do_inode_trans(
                error = EFSCORRUPTED;
                goto error;
        }
-       dicp = (xfs_icdinode_t *)(item->ri_buf[1].i_addr);
+       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,
@@ -2461,7 +2450,7 @@ xlog_recover_do_inode_trans(
        }
 
        /* The core is in in-core format */
-       xfs_dinode_to_disk(dip, (xfs_icdinode_t *)item->ri_buf[1].i_addr);
+       xfs_dinode_to_disk(dip, item->ri_buf[1].i_addr);
 
        /* the rest is in on-disk format */
        if (item->ri_buf[1].i_len > sizeof(struct xfs_icdinode)) {
@@ -2578,7 +2567,7 @@ xlog_recover_do_quotaoff_trans(
                return (0);
        }
 
-       qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr;
+       qoff_f = item->ri_buf[0].i_addr;
        ASSERT(qoff_f);
 
        /*
@@ -2622,9 +2611,8 @@ xlog_recover_do_dquot_trans(
        if (mp->m_qflags == 0)
                return (0);
 
-       recddq = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr;
-
-       if (item->ri_buf[1].i_addr == NULL) {
+       recddq = item->ri_buf[1].i_addr;
+       if (recddq == NULL) {
                cmn_err(CE_ALERT,
                        "XFS: NULL dquot in %s.", __func__);
                return XFS_ERROR(EIO);
@@ -2654,7 +2642,7 @@ xlog_recover_do_dquot_trans(
         * The other possibility, of course, is that the quota subsystem was
         * removed since the last mount - ENOSYS.
         */
-       dq_f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr;
+       dq_f = item->ri_buf[0].i_addr;
        ASSERT(dq_f);
        if ((error = xfs_qm_dqcheck(recddq,
                           dq_f->qlf_id,
@@ -2721,7 +2709,7 @@ xlog_recover_do_efi_trans(
                return 0;
        }
 
-       efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
+       efi_formatp = item->ri_buf[0].i_addr;
 
        mp = log->l_mp;
        efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
@@ -2767,7 +2755,7 @@ xlog_recover_do_efd_trans(
                return;
        }
 
-       efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
+       efd_formatp = item->ri_buf[0].i_addr;
        ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) +
                ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) ||
               (item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) +
index 69f62d8b2816c52389f4947c9d86b3958ccf57a6..aeb9d72ebf6e55102bb4b7a98dbaa60264511165 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
index 5761087ee8ea31be3e4c571630ceca807485e5e3..622da2179a57bd1546d84d2a1cba26202c627135 100644 (file)
@@ -66,65 +66,6 @@ struct xfs_nameops;
 struct xfs_ail;
 struct xfs_quotainfo;
 
-
-/*
- * Prototypes and functions for the Data Migration subsystem.
- */
-
-typedef int    (*xfs_send_data_t)(int, struct xfs_inode *,
-                       xfs_off_t, size_t, int, int *);
-typedef int    (*xfs_send_mmap_t)(struct vm_area_struct *, uint);
-typedef int    (*xfs_send_destroy_t)(struct xfs_inode *, dm_right_t);
-typedef int    (*xfs_send_namesp_t)(dm_eventtype_t, struct xfs_mount *,
-                       struct xfs_inode *, dm_right_t,
-                       struct xfs_inode *, dm_right_t,
-                       const unsigned char *, const unsigned char *,
-                       mode_t, int, int);
-typedef int    (*xfs_send_mount_t)(struct xfs_mount *, dm_right_t,
-                       char *, char *);
-typedef void   (*xfs_send_unmount_t)(struct xfs_mount *, struct xfs_inode *,
-                       dm_right_t, mode_t, int, int);
-
-typedef struct xfs_dmops {
-       xfs_send_data_t         xfs_send_data;
-       xfs_send_mmap_t         xfs_send_mmap;
-       xfs_send_destroy_t      xfs_send_destroy;
-       xfs_send_namesp_t       xfs_send_namesp;
-       xfs_send_mount_t        xfs_send_mount;
-       xfs_send_unmount_t      xfs_send_unmount;
-} xfs_dmops_t;
-
-#define XFS_DMAPI_UNMOUNT_FLAGS(mp) \
-       (((mp)->m_dmevmask & (1 << DM_EVENT_UNMOUNT)) ? 0 : DM_FLAGS_UNWANTED)
-
-#define XFS_SEND_DATA(mp, ev,ip,off,len,fl,lock) \
-       (*(mp)->m_dm_ops->xfs_send_data)(ev,ip,off,len,fl,lock)
-#define XFS_SEND_MMAP(mp, vma,fl) \
-       (*(mp)->m_dm_ops->xfs_send_mmap)(vma,fl)
-#define XFS_SEND_DESTROY(mp, ip,right) \
-       (*(mp)->m_dm_ops->xfs_send_destroy)(ip,right)
-#define XFS_SEND_NAMESP(mp, ev,b1,r1,b2,r2,n1,n2,mode,rval,fl) \
-       (*(mp)->m_dm_ops->xfs_send_namesp)(ev,NULL,b1,r1,b2,r2,n1,n2,mode,rval,fl)
-#define XFS_SEND_MOUNT(mp,right,path,name) \
-       (*(mp)->m_dm_ops->xfs_send_mount)(mp,right,path,name)
-#define XFS_SEND_PREUNMOUNT(mp) \
-do { \
-       if (mp->m_flags & XFS_MOUNT_DMAPI) { \
-               (*(mp)->m_dm_ops->xfs_send_namesp)(DM_EVENT_PREUNMOUNT, mp, \
-                       (mp)->m_rootip, DM_RIGHT_NULL, \
-                       (mp)->m_rootip, DM_RIGHT_NULL, \
-                       NULL, NULL, 0, 0, XFS_DMAPI_UNMOUNT_FLAGS(mp)); \
-       } \
-} while (0)
-#define XFS_SEND_UNMOUNT(mp) \
-do { \
-       if (mp->m_flags & XFS_MOUNT_DMAPI) { \
-               (*(mp)->m_dm_ops->xfs_send_unmount)(mp, (mp)->m_rootip, \
-                       DM_RIGHT_NULL, 0, 0, XFS_DMAPI_UNMOUNT_FLAGS(mp)); \
-       } \
-} while (0)
-
-
 #ifdef HAVE_PERCPU_SB
 
 /*
@@ -241,8 +182,6 @@ typedef struct xfs_mount {
        uint                    m_chsize;       /* size of next field */
        struct xfs_chash        *m_chash;       /* fs private inode per-cluster
                                                 * hash table */
-       struct xfs_dmops        *m_dm_ops;      /* vector of DMI ops */
-       struct xfs_qmops        *m_qm_ops;      /* vector of XQM ops */
        atomic_t                m_active_trans; /* number trans frozen */
 #ifdef HAVE_PERCPU_SB
        xfs_icsb_cnts_t __percpu *m_sb_cnts;    /* per-cpu superblock counters */
@@ -269,7 +208,6 @@ typedef struct xfs_mount {
                                                   must be synchronous except
                                                   for space allocations */
 #define XFS_MOUNT_DELAYLOG     (1ULL << 1)     /* delayed logging is enabled */
-#define XFS_MOUNT_DMAPI                (1ULL << 2)     /* dmapi is enabled */
 #define XFS_MOUNT_WAS_CLEAN    (1ULL << 3)
 #define XFS_MOUNT_FS_SHUTDOWN  (1ULL << 4)     /* atomic stop of all filesystem
                                                   operations, typically for
@@ -282,8 +220,6 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_GRPID                (1ULL << 9)     /* group-ID assigned from directory */
 #define XFS_MOUNT_NORECOVERY   (1ULL << 10)    /* no recovery - dirty fs */
 #define XFS_MOUNT_DFLT_IOSIZE  (1ULL << 12)    /* set default i/o size */
-#define XFS_MOUNT_OSYNCISOSYNC (1ULL << 13)    /* o_sync is REALLY o_sync */
-                                               /* osyncisdsync is now default*/
 #define XFS_MOUNT_32BITINODES  (1ULL << 14)    /* do not create inodes above
                                                 * 32 bits in size */
 #define XFS_MOUNT_SMALL_INUMS  (1ULL << 15)    /* users wants 32bit inodes */
@@ -440,11 +376,6 @@ extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
 
 extern int     xfs_dev_is_read_only(struct xfs_mount *, char *);
 
-extern int     xfs_dmops_get(struct xfs_mount *);
-extern void    xfs_dmops_put(struct xfs_mount *);
-
-extern struct xfs_dmops xfs_dmcore_xfs;
-
 #endif /* __KERNEL__ */
 
 extern void    xfs_mod_sb(struct xfs_trans *, __int64_t);
index fc1cda23b8171552ff6fd99d34adebf6be782bb3..8fca957200dfcba000f1f0eb4da51eb1d4f8516e 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
@@ -116,20 +113,7 @@ xfs_rename(
        int             spaceres;
        int             num_inodes;
 
-       xfs_itrace_entry(src_dp);
-       xfs_itrace_entry(target_dp);
-
-       if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) ||
-           DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
-                                       src_dp, DM_RIGHT_NULL,
-                                       target_dp, DM_RIGHT_NULL,
-                                       src_name->name, target_name->name,
-                                       0, 0, 0);
-               if (error)
-                       return error;
-       }
-       /* Return through std_return after this point. */
+       trace_xfs_rename(src_dp, target_dp, src_name, target_name);
 
        new_parent = (src_dp != target_dp);
        src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR);
@@ -184,26 +168,14 @@ xfs_rename(
        /*
         * Join all the inodes to the transaction. From this point on,
         * we can rely on either trans_commit or trans_cancel to unlock
-        * them.  Note that we need to add a vnode reference to the
-        * directories since trans_commit & trans_cancel will decrement
-        * them when they unlock the inodes.  Also, we need to be careful
-        * not to add an inode to the transaction more than once.
+        * them.
         */
-       IHOLD(src_dp);
-       xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
-
-       if (new_parent) {
-               IHOLD(target_dp);
-               xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
-       }
-
-       IHOLD(src_ip);
-       xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
-
-       if (target_ip) {
-               IHOLD(target_ip);
-               xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
-       }
+       xfs_trans_ijoin_ref(tp, src_dp, XFS_ILOCK_EXCL);
+       if (new_parent)
+               xfs_trans_ijoin_ref(tp, target_dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, src_ip, XFS_ILOCK_EXCL);
+       if (target_ip)
+               xfs_trans_ijoin_ref(tp, target_ip, XFS_ILOCK_EXCL);
 
        /*
         * If we are using project inheritance, we only allow renames
@@ -369,26 +341,13 @@ xfs_rename(
         * trans_commit will unlock src_ip, target_ip & decrement
         * the vnode references.
         */
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-
-       /* Fall through to std_return with error = 0 or errno from
-        * xfs_trans_commit      */
-std_return:
-       if (DM_EVENT_ENABLED(src_dp, DM_EVENT_POSTRENAME) ||
-           DM_EVENT_ENABLED(target_dp, DM_EVENT_POSTRENAME)) {
-               (void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME,
-                                       src_dp, DM_RIGHT_NULL,
-                                       target_dp, DM_RIGHT_NULL,
-                                       src_name->name, target_name->name,
-                                       0, error, 0);
-       }
-       return error;
+       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 
  abort_return:
        cancel_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
  error_return:
        xfs_bmap_cancel(&free_list);
        xfs_trans_cancel(tp, cancel_flags);
-       goto std_return;
+ std_return:
+       return error;
 }
index a2d32ce335aa681c3beab111f4c844873353f6af..891260fea11e3bc442f2de17349f16d532fad6a9 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
@@ -129,7 +122,7 @@ xfs_growfs_rt_alloc(
                cancelflags |= XFS_TRANS_ABORT;
                error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks,
                        XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock,
-                       resblks, &map, &nmap, &flist, NULL);
+                       resblks, &map, &nmap, &flist);
                if (!error && nmap < 1)
                        error = XFS_ERROR(ENOSPC);
                if (error)
index e336742a58a47a467a24abb0688b8c1fe7853207..56861d5daaef54432a94a640a7b1e65812030ef7 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_itable.h"
-#include "xfs_btree.h"
-#include "xfs_alloc.h"
-#include "xfs_ialloc.h"
-#include "xfs_attr.h"
-#include "xfs_bmap.h"
 #include "xfs_error.h"
-#include "xfs_buf_item.h"
 #include "xfs_rw.h"
-#include "xfs_trace.h"
 
 /*
  * Force a shutdown of the filesystem instantly while keeping
index 28547dfce037643fb19744ed36906d5e7f3c1c76..fdca7416c754636a26dae9a312003932f7306d9f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (C) 2010 Red Hat, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_error.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
@@ -47,6 +44,7 @@
 #include "xfs_trace.h"
 
 kmem_zone_t    *xfs_trans_zone;
+kmem_zone_t    *xfs_log_item_desc_zone;
 
 
 /*
@@ -597,8 +595,7 @@ _xfs_trans_alloc(
        tp->t_magic = XFS_TRANS_MAGIC;
        tp->t_type = type;
        tp->t_mountp = mp;
-       tp->t_items_free = XFS_LIC_NUM_SLOTS;
-       xfs_lic_init(&(tp->t_items));
+       INIT_LIST_HEAD(&tp->t_items);
        INIT_LIST_HEAD(&tp->t_busy);
        return tp;
 }
@@ -643,8 +640,7 @@ xfs_trans_dup(
        ntp->t_magic = XFS_TRANS_MAGIC;
        ntp->t_type = tp->t_type;
        ntp->t_mountp = tp->t_mountp;
-       ntp->t_items_free = XFS_LIC_NUM_SLOTS;
-       xfs_lic_init(&(ntp->t_items));
+       INIT_LIST_HEAD(&ntp->t_items);
        INIT_LIST_HEAD(&ntp->t_busy);
 
        ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
@@ -1123,6 +1119,108 @@ xfs_trans_unreserve_and_mod_sb(
        }
 }
 
+/*
+ * Add the given log item to the transaction's list of log items.
+ *
+ * The log item will now point to its new descriptor with its li_desc field.
+ */
+void
+xfs_trans_add_item(
+       struct xfs_trans        *tp,
+       struct xfs_log_item     *lip)
+{
+       struct xfs_log_item_desc *lidp;
+
+       ASSERT(lip->li_mountp = tp->t_mountp);
+       ASSERT(lip->li_ailp = tp->t_mountp->m_ail);
+
+       lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS);
+
+       lidp->lid_item = lip;
+       lidp->lid_flags = 0;
+       lidp->lid_size = 0;
+       list_add_tail(&lidp->lid_trans, &tp->t_items);
+
+       lip->li_desc = lidp;
+}
+
+STATIC void
+xfs_trans_free_item_desc(
+       struct xfs_log_item_desc *lidp)
+{
+       list_del_init(&lidp->lid_trans);
+       kmem_zone_free(xfs_log_item_desc_zone, lidp);
+}
+
+/*
+ * Unlink and free the given descriptor.
+ */
+void
+xfs_trans_del_item(
+       struct xfs_log_item     *lip)
+{
+       xfs_trans_free_item_desc(lip->li_desc);
+       lip->li_desc = NULL;
+}
+
+/*
+ * Unlock all of the items of a transaction and free all the descriptors
+ * of that transaction.
+ */
+STATIC void
+xfs_trans_free_items(
+       struct xfs_trans        *tp,
+       xfs_lsn_t               commit_lsn,
+       int                     flags)
+{
+       struct xfs_log_item_desc *lidp, *next;
+
+       list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
+               struct xfs_log_item     *lip = lidp->lid_item;
+
+               lip->li_desc = NULL;
+
+               if (commit_lsn != NULLCOMMITLSN)
+                       IOP_COMMITTING(lip, commit_lsn);
+               if (flags & XFS_TRANS_ABORT)
+                       lip->li_flags |= XFS_LI_ABORTED;
+               IOP_UNLOCK(lip);
+
+               xfs_trans_free_item_desc(lidp);
+       }
+}
+
+/*
+ * Unlock the items associated with a transaction.
+ *
+ * Items which were not logged should be freed.  Those which were logged must
+ * still be tracked so they can be unpinned when the transaction commits.
+ */
+STATIC void
+xfs_trans_unlock_items(
+       struct xfs_trans        *tp,
+       xfs_lsn_t               commit_lsn)
+{
+       struct xfs_log_item_desc *lidp, *next;
+
+       list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
+               struct xfs_log_item     *lip = lidp->lid_item;
+
+               lip->li_desc = NULL;
+
+               if (commit_lsn != NULLCOMMITLSN)
+                       IOP_COMMITTING(lip, commit_lsn);
+               IOP_UNLOCK(lip);
+
+               /*
+                * Free the descriptor if the item is not dirty
+                * within this transaction.
+                */
+               if (!(lidp->lid_flags & XFS_LID_DIRTY))
+                       xfs_trans_free_item_desc(lidp);
+       }
+}
+
 /*
  * Total up the number of log iovecs needed to commit this
  * transaction.  The transaction itself needs one for the
@@ -1134,30 +1232,27 @@ xfs_trans_count_vecs(
        struct xfs_trans        *tp)
 {
        int                     nvecs;
-       xfs_log_item_desc_t     *lidp;
+       struct xfs_log_item_desc *lidp;
 
        nvecs = 1;
-       lidp = xfs_trans_first_item(tp);
-       ASSERT(lidp != NULL);
 
        /* In the non-debug case we need to start bailing out if we
         * didn't find a log_item here, return zero and let trans_commit
         * deal with it.
         */
-       if (lidp == NULL)
+       if (list_empty(&tp->t_items)) {
+               ASSERT(0);
                return 0;
+       }
 
-       while (lidp != NULL) {
+       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                /*
                 * Skip items which aren't dirty in this transaction.
                 */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
-                       lidp = xfs_trans_next_item(tp, lidp);
+               if (!(lidp->lid_flags & XFS_LID_DIRTY))
                        continue;
-               }
                lidp->lid_size = IOP_SIZE(lidp->lid_item);
                nvecs += lidp->lid_size;
-               lidp = xfs_trans_next_item(tp, lidp);
        }
 
        return nvecs;
@@ -1177,7 +1272,7 @@ xfs_trans_fill_vecs(
        struct xfs_trans        *tp,
        struct xfs_log_iovec    *log_vector)
 {
-       xfs_log_item_desc_t     *lidp;
+       struct xfs_log_item_desc *lidp;
        struct xfs_log_iovec    *vecp;
        uint                    nitems;
 
@@ -1188,14 +1283,11 @@ xfs_trans_fill_vecs(
        vecp = log_vector + 1;
 
        nitems = 0;
-       lidp = xfs_trans_first_item(tp);
-       ASSERT(lidp);
-       while (lidp) {
+       ASSERT(!list_empty(&tp->t_items));
+       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                /* Skip items which aren't dirty in this transaction. */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
-                       lidp = xfs_trans_next_item(tp, lidp);
+               if (!(lidp->lid_flags & XFS_LID_DIRTY))
                        continue;
-               }
 
                /*
                 * The item may be marked dirty but not log anything.  This can
@@ -1206,7 +1298,6 @@ xfs_trans_fill_vecs(
                IOP_FORMAT(lidp->lid_item, vecp);
                vecp += lidp->lid_size;
                IOP_PIN(lidp->lid_item);
-               lidp = xfs_trans_next_item(tp, lidp);
        }
 
        /*
@@ -1284,7 +1375,7 @@ xfs_trans_item_committed(
         * log item flags, if anyone else stales the buffer we do not want to
         * pay any attention to it.
         */
-       IOP_UNPIN(lip);
+       IOP_UNPIN(lip, 0);
 }
 
 /*
@@ -1301,24 +1392,15 @@ xfs_trans_committed(
        struct xfs_trans        *tp,
        int                     abortflag)
 {
-       xfs_log_item_desc_t     *lidp;
-       xfs_log_item_chunk_t    *licp;
-       xfs_log_item_chunk_t    *next_licp;
+       struct xfs_log_item_desc *lidp, *next;
 
        /* Call the transaction's completion callback if there is one. */
        if (tp->t_callback != NULL)
                tp->t_callback(tp, tp->t_callarg);
 
-       for (lidp = xfs_trans_first_item(tp);
-            lidp != NULL;
-            lidp = xfs_trans_next_item(tp, lidp)) {
+       list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
                xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
-       }
-
-       /* free the item chunks, ignoring the embedded chunk */
-       for (licp = tp->t_items.lic_next; licp != NULL; licp = next_licp) {
-               next_licp = licp->lic_next;
-               kmem_free(licp);
+               xfs_trans_free_item_desc(lidp);
        }
 
        xfs_trans_free(tp);
@@ -1333,16 +1415,14 @@ xfs_trans_uncommit(
        struct xfs_trans        *tp,
        uint                    flags)
 {
-       xfs_log_item_desc_t     *lidp;
+       struct xfs_log_item_desc *lidp;
 
-       for (lidp = xfs_trans_first_item(tp);
-            lidp != NULL;
-            lidp = xfs_trans_next_item(tp, lidp)) {
+       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                /*
                 * Unpin all but those that aren't dirty.
                 */
                if (lidp->lid_flags & XFS_LID_DIRTY)
-                       IOP_UNPIN_REMOVE(lidp->lid_item, tp);
+                       IOP_UNPIN(lidp->lid_item, 1);
        }
 
        xfs_trans_unreserve_and_mod_sb(tp);
@@ -1508,33 +1588,28 @@ STATIC struct xfs_log_vec *
 xfs_trans_alloc_log_vecs(
        xfs_trans_t     *tp)
 {
-       xfs_log_item_desc_t     *lidp;
+       struct xfs_log_item_desc *lidp;
        struct xfs_log_vec      *lv = NULL;
        struct xfs_log_vec      *ret_lv = NULL;
 
-       lidp = xfs_trans_first_item(tp);
 
        /* Bail out if we didn't find a log item.  */
-       if (!lidp) {
+       if (list_empty(&tp->t_items)) {
                ASSERT(0);
                return NULL;
        }
 
-       while (lidp != NULL) {
+       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                struct xfs_log_vec *new_lv;
 
                /* Skip items which aren't dirty in this transaction. */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
-                       lidp = xfs_trans_next_item(tp, lidp);
+               if (!(lidp->lid_flags & XFS_LID_DIRTY))
                        continue;
-               }
 
                /* Skip items that do not have any vectors for writing */
                lidp->lid_size = IOP_SIZE(lidp->lid_item);
-               if (!lidp->lid_size) {
-                       lidp = xfs_trans_next_item(tp, lidp);
+               if (!lidp->lid_size)
                        continue;
-               }
 
                new_lv = kmem_zalloc(sizeof(*new_lv) +
                                lidp->lid_size * sizeof(struct xfs_log_iovec),
@@ -1549,7 +1624,6 @@ xfs_trans_alloc_log_vecs(
                else
                        lv->lv_next = new_lv;
                lv = new_lv;
-               lidp = xfs_trans_next_item(tp, lidp);
        }
 
        return ret_lv;
@@ -1708,12 +1782,6 @@ xfs_trans_cancel(
        int                     flags)
 {
        int                     log_flags;
-#ifdef DEBUG
-       xfs_log_item_chunk_t    *licp;
-       xfs_log_item_desc_t     *lidp;
-       xfs_log_item_t          *lip;
-       int                     i;
-#endif
        xfs_mount_t             *mp = tp->t_mountp;
 
        /*
@@ -1732,21 +1800,11 @@ xfs_trans_cancel(
                xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
        }
 #ifdef DEBUG
-       if (!(flags & XFS_TRANS_ABORT)) {
-               licp = &(tp->t_items);
-               while (licp != NULL) {
-                       lidp = licp->lic_descs;
-                       for (i = 0; i < licp->lic_unused; i++, lidp++) {
-                               if (xfs_lic_isfree(licp, i)) {
-                                       continue;
-                               }
-
-                               lip = lidp->lid_item;
-                               if (!XFS_FORCED_SHUTDOWN(mp))
-                                       ASSERT(!(lip->li_type == XFS_LI_EFD));
-                       }
-                       licp = licp->lic_next;
-               }
+       if (!(flags & XFS_TRANS_ABORT) && !XFS_FORCED_SHUTDOWN(mp)) {
+               struct xfs_log_item_desc *lidp;
+
+               list_for_each_entry(lidp, &tp->t_items, lid_trans)
+                       ASSERT(!(lidp->lid_item->li_type == XFS_LI_EFD));
        }
 #endif
        xfs_trans_unreserve_and_mod_sb(tp);
@@ -1834,7 +1892,6 @@ xfs_trans_roll(
        if (error)
                return error;
 
-       xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(trans, dp);
+       xfs_trans_ijoin(trans, dp);
        return 0;
 }
index e639e8e9a2a978ed6404725ce52b6f4cdbe840ba..c13c0f97b4945d7ff80990aeb7d4c0a8e12d0139 100644 (file)
@@ -161,105 +161,14 @@ typedef struct xfs_trans_header {
  * the amount of space needed to log the item it describes
  * once we get to commit processing (see xfs_trans_commit()).
  */
-typedef struct xfs_log_item_desc {
+struct xfs_log_item_desc {
        struct xfs_log_item     *lid_item;
-       ushort          lid_size;
-       unsigned char   lid_flags;
-       unsigned char   lid_index;
-} xfs_log_item_desc_t;
+       ushort                  lid_size;
+       unsigned char           lid_flags;
+       struct list_head        lid_trans;
+};
 
 #define XFS_LID_DIRTY          0x1
-#define XFS_LID_PINNED         0x2
-
-/*
- * This structure is used to maintain a chunk list of log_item_desc
- * structures. The free field is a bitmask indicating which descriptors
- * in this chunk's array are free.  The unused field is the first value
- * not used since this chunk was allocated.
- */
-#define        XFS_LIC_NUM_SLOTS       15
-typedef struct xfs_log_item_chunk {
-       struct xfs_log_item_chunk       *lic_next;
-       ushort                          lic_free;
-       ushort                          lic_unused;
-       xfs_log_item_desc_t             lic_descs[XFS_LIC_NUM_SLOTS];
-} xfs_log_item_chunk_t;
-
-#define        XFS_LIC_MAX_SLOT        (XFS_LIC_NUM_SLOTS - 1)
-#define        XFS_LIC_FREEMASK        ((1 << XFS_LIC_NUM_SLOTS) - 1)
-
-
-/*
- * Initialize the given chunk.  Set the chunk's free descriptor mask
- * to indicate that all descriptors are free.  The caller gets to set
- * lic_unused to the right value (0 matches all free).  The
- * lic_descs.lid_index values are set up as each desc is allocated.
- */
-static inline void xfs_lic_init(xfs_log_item_chunk_t *cp)
-{
-       cp->lic_free = XFS_LIC_FREEMASK;
-}
-
-static inline void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot)
-{
-       cp->lic_descs[slot].lid_index = (unsigned char)(slot);
-}
-
-static inline int xfs_lic_vacancy(xfs_log_item_chunk_t *cp)
-{
-       return cp->lic_free & XFS_LIC_FREEMASK;
-}
-
-static inline void xfs_lic_all_free(xfs_log_item_chunk_t *cp)
-{
-       cp->lic_free = XFS_LIC_FREEMASK;
-}
-
-static inline int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp)
-{
-       return ((cp->lic_free & XFS_LIC_FREEMASK) == XFS_LIC_FREEMASK);
-}
-
-static inline int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot)
-{
-       return (cp->lic_free & (1 << slot));
-}
-
-static inline void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot)
-{
-       cp->lic_free &= ~(1 << slot);
-}
-
-static inline void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot)
-{
-       cp->lic_free |= 1 << slot;
-}
-
-static inline xfs_log_item_desc_t *
-xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot)
-{
-       return &(cp->lic_descs[slot]);
-}
-
-static inline int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp)
-{
-       return (uint)dp->lid_index;
-}
-
-/*
- * Calculate the address of a chunk given a descriptor pointer:
- * dp - dp->lid_index give the address of the start of the lic_descs array.
- * From this we subtract the offset of the lic_descs field in a chunk.
- * All of this yields the address of the chunk, which is
- * cast to a chunk pointer.
- */
-static inline xfs_log_item_chunk_t *
-xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
-{
-       return (xfs_log_item_chunk_t*) \
-               (((xfs_caddr_t)((dp) - (dp)->lid_index)) - \
-               (xfs_caddr_t)(((xfs_log_item_chunk_t*)0)->lic_descs));
-}
 
 #define        XFS_TRANS_MAGIC         0x5452414E      /* 'TRAN' */
 /*
@@ -275,8 +184,6 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
 /*
  * Values for call flags parameter.
  */
-#define        XFS_TRANS_NOSLEEP               0x1
-#define        XFS_TRANS_WAIT                  0x2
 #define        XFS_TRANS_RELEASE_LOG_RES       0x4
 #define        XFS_TRANS_ABORT                 0x8
 
@@ -438,8 +345,7 @@ typedef struct xfs_item_ops {
        uint (*iop_size)(xfs_log_item_t *);
        void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
        void (*iop_pin)(xfs_log_item_t *);
-       void (*iop_unpin)(xfs_log_item_t *);
-       void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *);
+       void (*iop_unpin)(xfs_log_item_t *, int remove);
        uint (*iop_trylock)(xfs_log_item_t *);
        void (*iop_unlock)(xfs_log_item_t *);
        xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
@@ -451,8 +357,7 @@ typedef struct xfs_item_ops {
 #define IOP_SIZE(ip)           (*(ip)->li_ops->iop_size)(ip)
 #define IOP_FORMAT(ip,vp)      (*(ip)->li_ops->iop_format)(ip, vp)
 #define IOP_PIN(ip)            (*(ip)->li_ops->iop_pin)(ip)
-#define IOP_UNPIN(ip)          (*(ip)->li_ops->iop_unpin)(ip)
-#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp)
+#define IOP_UNPIN(ip, remove)  (*(ip)->li_ops->iop_unpin)(ip, remove)
 #define IOP_TRYLOCK(ip)                (*(ip)->li_ops->iop_trylock)(ip)
 #define IOP_UNLOCK(ip)         (*(ip)->li_ops->iop_unlock)(ip)
 #define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
@@ -516,8 +421,7 @@ typedef struct xfs_trans {
        int64_t                 t_rblocks_delta;/* superblock rblocks change */
        int64_t                 t_rextents_delta;/* superblocks rextents chg */
        int64_t                 t_rextslog_delta;/* superblocks rextslog chg */
-       unsigned int            t_items_free;   /* log item descs free */
-       xfs_log_item_chunk_t    t_items;        /* first log item desc chunk */
+       struct list_head        t_items;        /* log item descriptors */
        xfs_trans_header_t      t_header;       /* header for in-log trans */
        struct list_head        t_busy;         /* list of busy extents */
        unsigned long           t_pflags;       /* saved process flags state */
@@ -569,8 +473,8 @@ 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_ijoin(xfs_trans_t *, struct xfs_inode *, uint);
-void           xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *);
+void           xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint);
+void           xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *);
 void           xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
 void           xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
 struct xfs_efi_log_item        *xfs_trans_get_efi(xfs_trans_t *, uint);
@@ -595,6 +499,7 @@ int         xfs_trans_ail_init(struct xfs_mount *);
 void           xfs_trans_ail_destroy(struct xfs_mount *);
 
 extern kmem_zone_t     *xfs_trans_zone;
+extern kmem_zone_t     *xfs_log_item_desc_zone;
 
 #endif /* __KERNEL__ */
 
index e799824f72451ff017175144994c3322040945a6..dc9069568ff7182db00b0cf6bf9008ea41aeff69 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
 #include "xfs_error.h"
index 63d81a22f4fd60c6d6abc93538c37e6480c8fd3b..90af025e6839e69a8fb32e49e76d810b2ceb9cf9 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_buf_item.h"
@@ -51,36 +47,17 @@ xfs_trans_buf_item_match(
        xfs_daddr_t             blkno,
        int                     len)
 {
-       xfs_log_item_chunk_t    *licp;
-       xfs_log_item_desc_t     *lidp;
-       xfs_buf_log_item_t      *blip;
-       int                     i;
+       struct xfs_log_item_desc *lidp;
+       struct xfs_buf_log_item *blip;
 
        len = BBTOB(len);
-       for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) {
-               if (xfs_lic_are_all_free(licp)) {
-                       ASSERT(licp == &tp->t_items);
-                       ASSERT(licp->lic_next == NULL);
-                       return NULL;
-               }
-
-               for (i = 0; i < licp->lic_unused; i++) {
-                       /*
-                        * Skip unoccupied slots.
-                        */
-                       if (xfs_lic_isfree(licp, i))
-                               continue;
-
-                       lidp = xfs_lic_slot(licp, i);
-                       blip = (xfs_buf_log_item_t *)lidp->lid_item;
-                       if (blip->bli_item.li_type != XFS_LI_BUF)
-                               continue;
-
-                       if (XFS_BUF_TARGET(blip->bli_buf) == target &&
-                           XFS_BUF_ADDR(blip->bli_buf) == blkno &&
-                           XFS_BUF_COUNT(blip->bli_buf) == len)
-                               return blip->bli_buf;
-               }
+       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
+               blip = (struct xfs_buf_log_item *)lidp->lid_item;
+               if (blip->bli_item.li_type == XFS_LI_BUF &&
+                   XFS_BUF_TARGET(blip->bli_buf) == target &&
+                   XFS_BUF_ADDR(blip->bli_buf) == blkno &&
+                   XFS_BUF_COUNT(blip->bli_buf) == len)
+                       return blip->bli_buf;
        }
 
        return NULL;
@@ -127,7 +104,7 @@ _xfs_trans_bjoin(
        /*
         * Get a log_item_desc to point at the new item.
         */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
+       xfs_trans_add_item(tp, &bip->bli_item);
 
        /*
         * Initialize b_fsprivate2 so we can find it with incore_match()
@@ -483,7 +460,6 @@ xfs_trans_brelse(xfs_trans_t        *tp,
 {
        xfs_buf_log_item_t      *bip;
        xfs_log_item_t          *lip;
-       xfs_log_item_desc_t     *lidp;
 
        /*
         * Default to a normal brelse() call if the tp is NULL.
@@ -514,13 +490,6 @@ xfs_trans_brelse(xfs_trans_t       *tp,
        ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
-       /*
-        * Find the item descriptor pointing to this buffer's
-        * log item.  It must be there.
-        */
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
-       ASSERT(lidp != NULL);
-
        trace_xfs_trans_brelse(bip);
 
        /*
@@ -536,7 +505,7 @@ xfs_trans_brelse(xfs_trans_t        *tp,
         * If the buffer is dirty within this transaction, we can't
         * release it until we commit.
         */
-       if (lidp->lid_flags & XFS_LID_DIRTY)
+       if (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY)
                return;
 
        /*
@@ -553,7 +522,7 @@ xfs_trans_brelse(xfs_trans_t        *tp,
        /*
         * Free up the log item descriptor tracking the released item.
         */
-       xfs_trans_free_item(tp, lidp);
+       xfs_trans_del_item(&bip->bli_item);
 
        /*
         * Clear the hold flag in the buf log item if it is set.
@@ -665,7 +634,6 @@ xfs_trans_log_buf(xfs_trans_t       *tp,
                  uint          last)
 {
        xfs_buf_log_item_t      *bip;
-       xfs_log_item_desc_t     *lidp;
 
        ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
@@ -690,7 +658,7 @@ xfs_trans_log_buf(xfs_trans_t       *tp,
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks);
-       bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))xfs_buf_iodone;
+       bip->bli_item.li_cb = xfs_buf_iodone;
 
        trace_xfs_trans_log_buf(bip);
 
@@ -707,11 +675,8 @@ xfs_trans_log_buf(xfs_trans_t      *tp,
                bip->bli_format.blf_flags &= ~XFS_BLF_CANCEL;
        }
 
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
-       ASSERT(lidp != NULL);
-
        tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
        bip->bli_flags |= XFS_BLI_LOGGED;
        xfs_buf_item_log(bip, first, last);
 }
@@ -740,7 +705,6 @@ xfs_trans_binval(
        xfs_trans_t     *tp,
        xfs_buf_t       *bp)
 {
-       xfs_log_item_desc_t     *lidp;
        xfs_buf_log_item_t      *bip;
 
        ASSERT(XFS_BUF_ISBUSY(bp));
@@ -748,8 +712,6 @@ xfs_trans_binval(
        ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
 
        bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
-       ASSERT(lidp != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
        trace_xfs_trans_binval(bip);
@@ -764,7 +726,7 @@ xfs_trans_binval(
                ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
                ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF));
                ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
-               ASSERT(lidp->lid_flags & XFS_LID_DIRTY);
+               ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY);
                ASSERT(tp->t_flags & XFS_TRANS_DIRTY);
                return;
        }
@@ -797,7 +759,7 @@ xfs_trans_binval(
        bip->bli_format.blf_flags |= XFS_BLF_CANCEL;
        memset((char *)(bip->bli_format.blf_data_map), 0,
              (bip->bli_format.blf_map_size * sizeof(uint)));
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
        tp->t_flags |= XFS_TRANS_DIRTY;
 }
 
@@ -853,12 +815,9 @@ xfs_trans_stale_inode_buf(
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
        bip->bli_flags |= XFS_BLI_STALE_INODE;
-       bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))
-               xfs_buf_iodone;
+       bip->bli_item.li_cb = xfs_buf_iodone;
 }
 
-
-
 /*
  * Mark the buffer as being one which contains newly allocated
  * inodes.  We need to make sure that even if this buffer is
index 27cce2a9c7e9108debaab50b96a92a2c0109cb39..f783d5e9fa70f30b87650a5dfe0fd09bbd80ba02 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
 #include "xfs_extfree_item.h"
@@ -49,9 +48,8 @@ xfs_trans_get_efi(xfs_trans_t *tp,
        /*
         * Get a log_item_desc to point at the new item.
         */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efip);
-
-       return (efip);
+       xfs_trans_add_item(tp, &efip->efi_item);
+       return efip;
 }
 
 /*
@@ -65,15 +63,11 @@ xfs_trans_log_efi_extent(xfs_trans_t                *tp,
                         xfs_fsblock_t          start_block,
                         xfs_extlen_t           ext_len)
 {
-       xfs_log_item_desc_t     *lidp;
        uint                    next_extent;
        xfs_extent_t            *extp;
 
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efip);
-       ASSERT(lidp != NULL);
-
        tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 
        next_extent = efip->efi_next_extent;
        ASSERT(next_extent < efip->efi_format.efi_nextents);
@@ -106,9 +100,8 @@ xfs_trans_get_efd(xfs_trans_t               *tp,
        /*
         * Get a log_item_desc to point at the new item.
         */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efdp);
-
-       return (efdp);
+       xfs_trans_add_item(tp, &efdp->efd_item);
+       return efdp;
 }
 
 /*
@@ -122,15 +115,11 @@ xfs_trans_log_efd_extent(xfs_trans_t              *tp,
                         xfs_fsblock_t          start_block,
                         xfs_extlen_t           ext_len)
 {
-       xfs_log_item_desc_t     *lidp;
        uint                    next_extent;
        xfs_extent_t            *extp;
 
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efdp);
-       ASSERT(lidp != NULL);
-
        tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 
        next_extent = efdp->efd_next_extent;
        ASSERT(next_extent < efdp->efd_format.efd_nextents);
index 2559dfec946bb990afe7e44af28ae43204d6474a..cdc53a1050c56ac365a2d61114f65d1cc03fbc26 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_trans_priv.h"
 #include "xfs_inode_item.h"
+#include "xfs_trace.h"
 
 #ifdef XFS_TRANS_DEBUG
 STATIC void
@@ -47,7 +43,6 @@ xfs_trans_inode_broot_debug(
 #define        xfs_trans_inode_broot_debug(ip)
 #endif
 
-
 /*
  * Get an inode and join it to the transaction.
  */
@@ -63,49 +58,39 @@ xfs_trans_iget(
        int                     error;
 
        error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp);
-       if (!error && tp)
-               xfs_trans_ijoin(tp, *ipp, lock_flags);
+       if (!error && tp) {
+               xfs_trans_ijoin(tp, *ipp);
+               (*ipp)->i_itemp->ili_lock_flags = lock_flags;
+       }
        return error;
 }
 
 /*
- * Add the locked inode to the transaction.
- * The inode must be locked, and it cannot be associated with any
- * transaction.  The caller must specify the locks already held
- * on the inode.
+ * Add a locked inode to the transaction.
+ *
+ * The inode must be locked, and it cannot be associated with any transaction.
  */
 void
 xfs_trans_ijoin(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       uint            lock_flags)
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip)
 {
        xfs_inode_log_item_t    *iip;
 
        ASSERT(ip->i_transp == NULL);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-       ASSERT(lock_flags & XFS_ILOCK_EXCL);
        if (ip->i_itemp == NULL)
                xfs_inode_item_init(ip, ip->i_mount);
        iip = ip->i_itemp;
-       ASSERT(iip->ili_flags == 0);
+       ASSERT(iip->ili_lock_flags == 0);
 
        /*
         * Get a log_item_desc to point at the new item.
         */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(iip));
+       xfs_trans_add_item(tp, &iip->ili_item);
 
        xfs_trans_inode_broot_debug(ip);
 
-       /*
-        * If the IO lock is already held, mark that in the inode log item.
-        */
-       if (lock_flags & XFS_IOLOCK_EXCL) {
-               iip->ili_flags |= XFS_ILI_IOLOCKED_EXCL;
-       } else if (lock_flags & XFS_IOLOCK_SHARED) {
-               iip->ili_flags |= XFS_ILI_IOLOCKED_SHARED;
-       }
-
        /*
         * Initialize i_transp so we can find it with xfs_inode_incore()
         * in xfs_trans_iget() above.
@@ -113,27 +98,25 @@ xfs_trans_ijoin(
        ip->i_transp = tp;
 }
 
-
-
 /*
- * Mark the inode as not needing to be unlocked when the inode item's
- * IOP_UNLOCK() routine is called.  The inode must already be locked
- * and associated with the given transaction.
+ * Add a locked inode to the transaction.
+ *
+ *
+ * Grabs a reference to the inode which will be dropped when the transaction
+ * is commited.  The inode will also be unlocked at that point.  The inode
+ * must be locked, and it cannot be associated with any transaction.
  */
-/*ARGSUSED*/
 void
-xfs_trans_ihold(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip)
+xfs_trans_ijoin_ref(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       uint                    lock_flags)
 {
-       ASSERT(ip->i_transp == tp);
-       ASSERT(ip->i_itemp != NULL);
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-       ip->i_itemp->ili_flags |= XFS_ILI_HOLD;
+       xfs_trans_ijoin(tp, ip);
+       IHOLD(ip);
+       ip->i_itemp->ili_lock_flags = lock_flags;
 }
 
-
 /*
  * This is called to mark the fields indicated in fieldmask as needing
  * to be logged when the transaction is committed.  The inode must
@@ -149,17 +132,12 @@ xfs_trans_log_inode(
        xfs_inode_t     *ip,
        uint            flags)
 {
-       xfs_log_item_desc_t     *lidp;
-
        ASSERT(ip->i_transp == tp);
        ASSERT(ip->i_itemp != NULL);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp));
-       ASSERT(lidp != NULL);
-
        tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
+       ip->i_itemp->ili_item.li_desc->lid_flags |= XFS_LID_DIRTY;
 
        /*
         * Always OR in the bits from the ili_last_fields field.
diff --git a/fs/xfs/xfs_trans_item.c b/fs/xfs/xfs_trans_item.c
deleted file mode 100644 (file)
index f11d37d..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 2000-2002,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 "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-/* XXX: from here down needed until struct xfs_trans has its own ailp */
-#include "xfs_bit.h"
-#include "xfs_buf_item.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
-#include "xfs_mount.h"
-
-STATIC int     xfs_trans_unlock_chunk(xfs_log_item_chunk_t *,
-                                       int, int, xfs_lsn_t);
-
-/*
- * This is called to add the given log item to the transaction's
- * list of log items.  It must find a free log item descriptor
- * or allocate a new one and add the item to that descriptor.
- * The function returns a pointer to item descriptor used to point
- * to the new item.  The log item will now point to its new descriptor
- * with its li_desc field.
- */
-xfs_log_item_desc_t *
-xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip)
-{
-       xfs_log_item_desc_t     *lidp;
-       xfs_log_item_chunk_t    *licp;
-       int                     i=0;
-
-       /*
-        * If there are no free descriptors, allocate a new chunk
-        * of them and put it at the front of the chunk list.
-        */
-       if (tp->t_items_free == 0) {
-               licp = (xfs_log_item_chunk_t*)
-                      kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP);
-               ASSERT(licp != NULL);
-               /*
-                * Initialize the chunk, and then
-                * claim the first slot in the newly allocated chunk.
-                */
-               xfs_lic_init(licp);
-               xfs_lic_claim(licp, 0);
-               licp->lic_unused = 1;
-               xfs_lic_init_slot(licp, 0);
-               lidp = xfs_lic_slot(licp, 0);
-
-               /*
-                * Link in the new chunk and update the free count.
-                */
-               licp->lic_next = tp->t_items.lic_next;
-               tp->t_items.lic_next = licp;
-               tp->t_items_free = XFS_LIC_NUM_SLOTS - 1;
-
-               /*
-                * Initialize the descriptor and the generic portion
-                * of the log item.
-                *
-                * Point the new slot at this item and return it.
-                * Also point the log item at its currently active
-                * descriptor and set the item's mount pointer.
-                */
-               lidp->lid_item = lip;
-               lidp->lid_flags = 0;
-               lidp->lid_size = 0;
-               lip->li_desc = lidp;
-               lip->li_mountp = tp->t_mountp;
-               lip->li_ailp = tp->t_mountp->m_ail;
-               return lidp;
-       }
-
-       /*
-        * Find the free descriptor. It is somewhere in the chunklist
-        * of descriptors.
-        */
-       licp = &tp->t_items;
-       while (licp != NULL) {
-               if (xfs_lic_vacancy(licp)) {
-                       if (licp->lic_unused <= XFS_LIC_MAX_SLOT) {
-                               i = licp->lic_unused;
-                               ASSERT(xfs_lic_isfree(licp, i));
-                               break;
-                       }
-                       for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) {
-                               if (xfs_lic_isfree(licp, i))
-                                       break;
-                       }
-                       ASSERT(i <= XFS_LIC_MAX_SLOT);
-                       break;
-               }
-               licp = licp->lic_next;
-       }
-       ASSERT(licp != NULL);
-       /*
-        * If we find a free descriptor, claim it,
-        * initialize it, and return it.
-        */
-       xfs_lic_claim(licp, i);
-       if (licp->lic_unused <= i) {
-               licp->lic_unused = i + 1;
-               xfs_lic_init_slot(licp, i);
-       }
-       lidp = xfs_lic_slot(licp, i);
-       tp->t_items_free--;
-       lidp->lid_item = lip;
-       lidp->lid_flags = 0;
-       lidp->lid_size = 0;
-       lip->li_desc = lidp;
-       lip->li_mountp = tp->t_mountp;
-       lip->li_ailp = tp->t_mountp->m_ail;
-       return lidp;
-}
-
-/*
- * Free the given descriptor.
- *
- * This requires setting the bit in the chunk's free mask corresponding
- * to the given slot.
- */
-void
-xfs_trans_free_item(xfs_trans_t        *tp, xfs_log_item_desc_t *lidp)
-{
-       uint                    slot;
-       xfs_log_item_chunk_t    *licp;
-       xfs_log_item_chunk_t    **licpp;
-
-       slot = xfs_lic_desc_to_slot(lidp);
-       licp = xfs_lic_desc_to_chunk(lidp);
-       xfs_lic_relse(licp, slot);
-       lidp->lid_item->li_desc = NULL;
-       tp->t_items_free++;
-
-       /*
-        * If there are no more used items in the chunk and this is not
-        * the chunk embedded in the transaction structure, then free
-        * the chunk. First pull it from the chunk list and then
-        * free it back to the heap.  We didn't bother with a doubly
-        * linked list here because the lists should be very short
-        * and this is not a performance path.  It's better to save
-        * the memory of the extra pointer.
-        *
-        * Also decrement the transaction structure's count of free items
-        * by the number in a chunk since we are freeing an empty chunk.
-        */
-       if (xfs_lic_are_all_free(licp) && (licp != &(tp->t_items))) {
-               licpp = &(tp->t_items.lic_next);
-               while (*licpp != licp) {
-                       ASSERT(*licpp != NULL);
-                       licpp = &((*licpp)->lic_next);
-               }
-               *licpp = licp->lic_next;
-               kmem_free(licp);
-               tp->t_items_free -= XFS_LIC_NUM_SLOTS;
-       }
-}
-
-/*
- * This is called to find the descriptor corresponding to the given
- * log item.  It returns a pointer to the descriptor.
- * The log item MUST have a corresponding descriptor in the given
- * transaction.  This routine does not return NULL, it panics.
- *
- * The descriptor pointer is kept in the log item's li_desc field.
- * Just return it.
- */
-/*ARGSUSED*/
-xfs_log_item_desc_t *
-xfs_trans_find_item(xfs_trans_t        *tp, xfs_log_item_t *lip)
-{
-       ASSERT(lip->li_desc != NULL);
-
-       return lip->li_desc;
-}
-
-
-/*
- * Return a pointer to the first descriptor in the chunk list.
- * This does not return NULL if there are none, it panics.
- *
- * The first descriptor must be in either the first or second chunk.
- * This is because the only chunk allowed to be empty is the first.
- * All others are freed when they become empty.
- *
- * At some point this and xfs_trans_next_item() should be optimized
- * to quickly look at the mask to determine if there is anything to
- * look at.
- */
-xfs_log_item_desc_t *
-xfs_trans_first_item(xfs_trans_t *tp)
-{
-       xfs_log_item_chunk_t    *licp;
-       int                     i;
-
-       licp = &tp->t_items;
-       /*
-        * If it's not in the first chunk, skip to the second.
-        */
-       if (xfs_lic_are_all_free(licp)) {
-               licp = licp->lic_next;
-       }
-
-       /*
-        * Return the first non-free descriptor in the chunk.
-        */
-       ASSERT(!xfs_lic_are_all_free(licp));
-       for (i = 0; i < licp->lic_unused; i++) {
-               if (xfs_lic_isfree(licp, i)) {
-                       continue;
-               }
-
-               return xfs_lic_slot(licp, i);
-       }
-       cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item");
-       return NULL;
-}
-
-
-/*
- * Given a descriptor, return the next descriptor in the chunk list.
- * This returns NULL if there are no more used descriptors in the list.
- *
- * We do this by first locating the chunk in which the descriptor resides,
- * and then scanning forward in the chunk and the list for the next
- * used descriptor.
- */
-/*ARGSUSED*/
-xfs_log_item_desc_t *
-xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
-{
-       xfs_log_item_chunk_t    *licp;
-       int                     i;
-
-       licp = xfs_lic_desc_to_chunk(lidp);
-
-       /*
-        * First search the rest of the chunk. The for loop keeps us
-        * from referencing things beyond the end of the chunk.
-        */
-       for (i = (int)xfs_lic_desc_to_slot(lidp) + 1; i < licp->lic_unused; i++) {
-               if (xfs_lic_isfree(licp, i)) {
-                       continue;
-               }
-
-               return xfs_lic_slot(licp, i);
-       }
-
-       /*
-        * Now search the next chunk.  It must be there, because the
-        * next chunk would have been freed if it were empty.
-        * If there is no next chunk, return NULL.
-        */
-       if (licp->lic_next == NULL) {
-               return NULL;
-       }
-
-       licp = licp->lic_next;
-       ASSERT(!xfs_lic_are_all_free(licp));
-       for (i = 0; i < licp->lic_unused; i++) {
-               if (xfs_lic_isfree(licp, i)) {
-                       continue;
-               }
-
-               return xfs_lic_slot(licp, i);
-       }
-       ASSERT(0);
-       /* NOTREACHED */
-       return NULL; /* keep gcc quite */
-}
-
-/*
- * This is called to unlock all of the items of a transaction and to free
- * all the descriptors of that transaction.
- *
- * It walks the list of descriptors and unlocks each item.  It frees
- * each chunk except that embedded in the transaction as it goes along.
- */
-void
-xfs_trans_free_items(
-       xfs_trans_t     *tp,
-       xfs_lsn_t       commit_lsn,
-       int             flags)
-{
-       xfs_log_item_chunk_t    *licp;
-       xfs_log_item_chunk_t    *next_licp;
-       int                     abort;
-
-       abort = flags & XFS_TRANS_ABORT;
-       licp = &tp->t_items;
-       /*
-        * Special case the embedded chunk so we don't free it below.
-        */
-       if (!xfs_lic_are_all_free(licp)) {
-               (void) xfs_trans_unlock_chunk(licp, 1, abort, commit_lsn);
-               xfs_lic_all_free(licp);
-               licp->lic_unused = 0;
-       }
-       licp = licp->lic_next;
-
-       /*
-        * Unlock each item in each chunk and free the chunks.
-        */
-       while (licp != NULL) {
-               ASSERT(!xfs_lic_are_all_free(licp));
-               (void) xfs_trans_unlock_chunk(licp, 1, abort, commit_lsn);
-               next_licp = licp->lic_next;
-               kmem_free(licp);
-               licp = next_licp;
-       }
-
-       /*
-        * Reset the transaction structure's free item count.
-        */
-       tp->t_items_free = XFS_LIC_NUM_SLOTS;
-       tp->t_items.lic_next = NULL;
-}
-
-
-
-/*
- * This is called to unlock the items associated with a transaction.
- * Items which were not logged should be freed.
- * Those which were logged must still be tracked so they can be unpinned
- * when the transaction commits.
- */
-void
-xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn)
-{
-       xfs_log_item_chunk_t    *licp;
-       xfs_log_item_chunk_t    *next_licp;
-       xfs_log_item_chunk_t    **licpp;
-       int                     freed;
-
-       freed = 0;
-       licp = &tp->t_items;
-
-       /*
-        * Special case the embedded chunk so we don't free.
-        */
-       if (!xfs_lic_are_all_free(licp)) {
-               freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn);
-       }
-       licpp = &(tp->t_items.lic_next);
-       licp = licp->lic_next;
-
-       /*
-        * Unlock each item in each chunk, free non-dirty descriptors,
-        * and free empty chunks.
-        */
-       while (licp != NULL) {
-               ASSERT(!xfs_lic_are_all_free(licp));
-               freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn);
-               next_licp = licp->lic_next;
-               if (xfs_lic_are_all_free(licp)) {
-                       *licpp = next_licp;
-                       kmem_free(licp);
-                       freed -= XFS_LIC_NUM_SLOTS;
-               } else {
-                       licpp = &(licp->lic_next);
-               }
-               ASSERT(*licpp == next_licp);
-               licp = next_licp;
-       }
-
-       /*
-        * Fix the free descriptor count in the transaction.
-        */
-       tp->t_items_free += freed;
-}
-
-/*
- * Unlock each item pointed to by a descriptor in the given chunk.
- * Stamp the commit lsn into each item if necessary.
- * Free descriptors pointing to items which are not dirty if freeing_chunk
- * is zero. If freeing_chunk is non-zero, then we need to unlock all
- * items in the chunk.
- * 
- * Return the number of descriptors freed.
- */
-STATIC int
-xfs_trans_unlock_chunk(
-       xfs_log_item_chunk_t    *licp,
-       int                     freeing_chunk,
-       int                     abort,
-       xfs_lsn_t               commit_lsn)
-{
-       xfs_log_item_desc_t     *lidp;
-       xfs_log_item_t          *lip;
-       int                     i;
-       int                     freed;
-
-       freed = 0;
-       lidp = licp->lic_descs;
-       for (i = 0; i < licp->lic_unused; i++, lidp++) {
-               if (xfs_lic_isfree(licp, i)) {
-                       continue;
-               }
-               lip = lidp->lid_item;
-               lip->li_desc = NULL;
-
-               if (commit_lsn != NULLCOMMITLSN)
-                       IOP_COMMITTING(lip, commit_lsn);
-               if (abort)
-                       lip->li_flags |= XFS_LI_ABORTED;
-               IOP_UNLOCK(lip);
-
-               /*
-                * Free the descriptor if the item is not dirty
-                * within this transaction and the caller is not
-                * going to just free the entire thing regardless.
-                */
-               if (!(freeing_chunk) &&
-                   (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) {
-                       xfs_lic_relse(licp, i);
-                       freed++;
-               }
-       }
-
-       return freed;
-}
index c6e4f2c8de6e8049a760b1510eb42beb54a295ae..e2d93d8ead7b68b9b6ab74b1869a3f8e10721981 100644 (file)
@@ -23,22 +23,8 @@ struct xfs_log_item_desc;
 struct xfs_mount;
 struct xfs_trans;
 
-/*
- * From xfs_trans_item.c
- */
-struct xfs_log_item_desc       *xfs_trans_add_item(struct xfs_trans *,
-                                           struct xfs_log_item *);
-void                           xfs_trans_free_item(struct xfs_trans *,
-                                           struct xfs_log_item_desc *);
-struct xfs_log_item_desc       *xfs_trans_find_item(struct xfs_trans *,
-                                            struct xfs_log_item *);
-struct xfs_log_item_desc       *xfs_trans_first_item(struct xfs_trans *);
-struct xfs_log_item_desc       *xfs_trans_next_item(struct xfs_trans *,
-                                            struct xfs_log_item_desc *);
-
-void   xfs_trans_unlock_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn);
-void   xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn,
-                               int flags);
+void   xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *);
+void   xfs_trans_del_item(struct xfs_log_item *);
 
 void   xfs_trans_item_committed(struct xfs_log_item *lip,
                                xfs_lsn_t commit_lsn, int aborted);
index 4d88616bde914ea4fe07696a30fdbd81fca878fa..b7d5769d2df04a6d5599fec813ce59693275c701 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_error.h"
 #include "xfs_quota.h"
-#include "xfs_rw.h"
 #include "xfs_itable.h"
 #include "xfs_utils.h"
 
@@ -324,86 +320,3 @@ xfs_bumplink(
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        return 0;
 }
-
-/*
- * Try to truncate the given file to 0 length.  Currently called
- * only out of xfs_remove when it has to truncate a file to free
- * up space for the remove to proceed.
- */
-int
-xfs_truncate_file(
-       xfs_mount_t     *mp,
-       xfs_inode_t     *ip)
-{
-       xfs_trans_t     *tp;
-       int             error;
-
-#ifdef QUOTADEBUG
-       /*
-        * This is called to truncate the quotainodes too.
-        */
-       if (XFS_IS_UQUOTA_ON(mp)) {
-               if (ip->i_ino != mp->m_sb.sb_uquotino)
-                       ASSERT(ip->i_udquot);
-       }
-       if (XFS_IS_OQUOTA_ON(mp)) {
-               if (ip->i_ino != mp->m_sb.sb_gquotino)
-                       ASSERT(ip->i_gdquot);
-       }
-#endif
-       /*
-        * Make the call to xfs_itruncate_start before starting the
-        * transaction, because we cannot make the call while we're
-        * in a transaction.
-        */
-       xfs_ilock(ip, XFS_IOLOCK_EXCL);
-       error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0);
-       if (error) {
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-               return error;
-       }
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
-       if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
-                                     XFS_TRANS_PERM_LOG_RES,
-                                     XFS_ITRUNCATE_LOG_COUNT))) {
-               xfs_trans_cancel(tp, 0);
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-               return error;
-       }
-
-       /*
-        * Follow the normal truncate locking protocol.  Since we
-        * hold the inode in the transaction, we know that its number
-        * of references will stay constant.
-        */
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
-       /*
-        * Signal a sync xaction.  The only case where that isn't
-        * the case is if we're truncating an already unlinked file
-        * on a wsync fs.  In that case, we know the blocks can't
-        * reappear in the file because the links to file are
-        * permanently toast.  Currently, we're always going to
-        * want a sync transaction because this code is being
-        * called from places where nlink is guaranteed to be 1
-        * but I'm leaving the tests in to protect against future
-        * changes -- rcc.
-        */
-       error = xfs_itruncate_finish(&tp, ip, (xfs_fsize_t)0,
-                                    XFS_DATA_FORK,
-                                    ((ip->i_d.di_nlink != 0 ||
-                                      !(mp->m_flags & XFS_MOUNT_WSYNC))
-                                     ? 1 : 0));
-       if (error) {
-               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
-                                XFS_TRANS_ABORT);
-       } else {
-               xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       }
-       xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
-       return error;
-}
index ef321225d2698cfa2f5982d24099388d0cdae0eb..f55b9678264f0edc8edb23b9aff16bab44b8f355 100644 (file)
@@ -18,7 +18,6 @@
 #ifndef __XFS_UTILS_H__
 #define __XFS_UTILS_H__
 
-extern int xfs_truncate_file(xfs_mount_t *, xfs_inode_t *);
 extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
                                xfs_dev_t, cred_t *, prid_t, int,
                                xfs_inode_t **, int *);
index c1646838898f45120767046f0b62d43cca92dd54..3ac137dd531bb5481b5ec04ef085de3a6506878d 100644 (file)
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir2.h"
-#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_itable.h"
-#include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
@@ -73,7 +68,7 @@ xfs_setattr(
        struct xfs_dquot        *udqp, *gdqp, *olddquot1, *olddquot2;
        int                     need_iolock = 1;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_setattr(ip);
 
        if (mp->m_flags & XFS_MOUNT_RDONLY)
                return XFS_ERROR(EROFS);
@@ -143,16 +138,6 @@ xfs_setattr(
                        goto error_return;
                }
        } else {
-               if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) &&
-                   !(flags & XFS_ATTR_DMI)) {
-                       int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR;
-                       code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip,
-                               iattr->ia_size, 0, dmflags, NULL);
-                       if (code) {
-                               lock_flags = 0;
-                               goto error_return;
-                       }
-               }
                if (need_iolock)
                        lock_flags |= XFS_IOLOCK_EXCL;
        }
@@ -283,8 +268,7 @@ xfs_setattr(
                commit_flags = XFS_TRANS_RELEASE_LOG_RES;
                xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-               xfs_trans_ijoin(tp, ip, lock_flags);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * Only change the c/mtime if we are changing the size
@@ -334,8 +318,7 @@ xfs_setattr(
                        xfs_iflags_set(ip, XFS_ITRUNCATED);
                }
        } else if (tp) {
-               xfs_trans_ijoin(tp, ip, lock_flags);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
        }
 
        /*
@@ -470,17 +453,10 @@ xfs_setattr(
                        return XFS_ERROR(code);
        }
 
-       if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) &&
-           !(flags & XFS_ATTR_DMI)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
-                                       NULL, DM_RIGHT_NULL, NULL, NULL,
-                                       0, 0, AT_DELAY_FLAG(flags));
-       }
        return 0;
 
  abort_return:
        commit_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
  error_return:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
@@ -516,7 +492,7 @@ xfs_readlink_bmap(
        int             error = 0;
 
        error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
-                       mval, &nmaps, NULL, NULL);
+                       mval, &nmaps, NULL);
        if (error)
                goto out;
 
@@ -557,7 +533,7 @@ xfs_readlink(
        int             pathlen;
        int             error = 0;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_readlink(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
@@ -613,14 +589,14 @@ xfs_free_eofblocks(
         */
        end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
        last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
-       map_len = last_fsb - end_fsb;
-       if (map_len <= 0)
+       if (last_fsb <= end_fsb)
                return 0;
+       map_len = last_fsb - end_fsb;
 
        nimaps = 1;
        xfs_ilock(ip, XFS_ILOCK_SHARED);
        error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
-                         NULL, 0, &imap, &nimaps, NULL, NULL);
+                         NULL, 0, &imap, &nimaps, NULL);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        if (!error && (nimaps != 0) &&
@@ -675,10 +651,7 @@ xfs_free_eofblocks(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip,
-                               XFS_IOLOCK_EXCL |
-                               XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                error = xfs_itruncate_finish(&tp, ip,
                                             ip->i_size,
@@ -750,8 +723,7 @@ xfs_inactive_symlink_rmt(
        xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
        size = (int)ip->i_d.di_size;
        ip->i_d.di_size = 0;
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Find the block(s) so we can inval and unmap them.
@@ -761,7 +733,7 @@ xfs_inactive_symlink_rmt(
        nmaps = ARRAY_SIZE(mval);
        if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
                        XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
-                       &free_list, NULL)))
+                       &free_list)))
                goto error0;
        /*
         * Invalidate the block(s).
@@ -776,7 +748,7 @@ xfs_inactive_symlink_rmt(
         * Unmap the dead block(s) to the free_list.
         */
        if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
-                       &first_block, &free_list, NULL, &done)))
+                       &first_block, &free_list, &done)))
                goto error1;
        ASSERT(done);
        /*
@@ -795,8 +767,7 @@ xfs_inactive_symlink_rmt(
         * Mark it dirty so it will be logged and moved forward in the log as
         * part of every commit.
         */
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Get a new, empty transaction to return to our caller.
@@ -929,8 +900,7 @@ xfs_inactive_attrs(
                goto error_cancel;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
        xfs_idestroy_fork(ip, XFS_ATTR_FORK);
 
        ASSERT(ip->i_d.di_anextents == 0);
@@ -1035,8 +1005,6 @@ xfs_inactive(
        int             error;
        int             truncate;
 
-       xfs_itrace_entry(ip);
-
        /*
         * If the inode is already free, then there can be nothing
         * to clean up here.
@@ -1060,9 +1028,6 @@ xfs_inactive(
 
        mp = ip->i_mount;
 
-       if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY))
-               XFS_SEND_DESTROY(mp, ip, DM_RIGHT_NULL);
-
        error = 0;
 
        /* If this is a read-only mount, don't do this (would generate I/O) */
@@ -1120,8 +1085,7 @@ xfs_inactive(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * normally, we have to run xfs_itruncate_finish sync.
@@ -1154,8 +1118,7 @@ xfs_inactive(
                        return VN_INACTIVE_CACHE;
                }
 
-               xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
        } else {
                error = xfs_trans_reserve(tp, 0,
                                          XFS_IFREE_LOG_RES(mp),
@@ -1168,8 +1131,7 @@ xfs_inactive(
                }
 
                xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
        }
 
        /*
@@ -1257,7 +1219,7 @@ xfs_lookup(
        int                     error;
        uint                    lock_mode;
 
-       xfs_itrace_entry(dp);
+       trace_xfs_lookup(dp, name);
 
        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
                return XFS_ERROR(EIO);
@@ -1309,21 +1271,11 @@ xfs_create(
        uint                    log_res;
        uint                    log_count;
 
-       xfs_itrace_entry(dp);
+       trace_xfs_create(dp, name);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
-                               dp, DM_RIGHT_NULL, NULL,
-                               DM_RIGHT_NULL, name->name, NULL,
-                               mode, 0, 0);
-
-               if (error)
-                       return error;
-       }
-
        if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
                prid = dp->i_d.di_projid;
        else
@@ -1427,8 +1379,7 @@ xfs_create(
         * the transaction cancel unlocking dp so don't do it explicitly in the
         * error path.
         */
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
        unlock_dp_on_error = B_FALSE;
 
        error = xfs_dir_createname(tp, dp, name, ip->i_ino,
@@ -1487,16 +1438,7 @@ xfs_create(
        xfs_qm_dqrele(gdqp);
 
        *ipp = ip;
-
-       /* Fallthrough to std_return with error = 0  */
- std_return:
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
-               XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, dp, DM_RIGHT_NULL,
-                               ip, DM_RIGHT_NULL, name->name, NULL, mode,
-                               error, 0);
-       }
-
-       return error;
+       return 0;
 
  out_bmap_cancel:
        xfs_bmap_cancel(&free_list);
@@ -1510,8 +1452,8 @@ xfs_create(
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       goto std_return;
+ std_return:
+       return error;
 
  out_abort_rele:
        /*
@@ -1726,20 +1668,11 @@ xfs_remove(
        uint                    resblks;
        uint                    log_count;
 
-       xfs_itrace_entry(dp);
-       xfs_itrace_entry(ip);
+       trace_xfs_remove(dp, name);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dp, DM_RIGHT_NULL,
-                                       NULL, DM_RIGHT_NULL, name->name, NULL,
-                                       ip->i_d.di_mode, 0, 0);
-               if (error)
-                       return error;
-       }
-
        error = xfs_qm_dqattach(dp, 0);
        if (error)
                goto std_return;
@@ -1782,15 +1715,8 @@ xfs_remove(
 
        xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
 
-       /*
-        * At this point, we've gotten both the directory and the entry
-        * inodes locked.
-        */
-       IHOLD(ip);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
 
        /*
         * If we're removing a directory perform some additional validation.
@@ -1877,21 +1803,15 @@ xfs_remove(
        if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
                xfs_filestream_deassociate(ip);
 
- std_return:
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) {
-               XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dp, DM_RIGHT_NULL,
-                               NULL, DM_RIGHT_NULL, name->name, NULL,
-                               ip->i_d.di_mode, error, 0);
-       }
-
-       return error;
+       return 0;
 
  out_bmap_cancel:
        xfs_bmap_cancel(&free_list);
        cancel_flags |= XFS_TRANS_ABORT;
  out_trans_cancel:
        xfs_trans_cancel(tp, cancel_flags);
-       goto std_return;
+ std_return:
+       return error;
 }
 
 int
@@ -1909,25 +1829,13 @@ xfs_link(
        int                     committed;
        int                     resblks;
 
-       xfs_itrace_entry(tdp);
-       xfs_itrace_entry(sip);
+       trace_xfs_link(tdp, target_name);
 
        ASSERT(!S_ISDIR(sip->i_d.di_mode));
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK,
-                                       tdp, DM_RIGHT_NULL,
-                                       sip, DM_RIGHT_NULL,
-                                       target_name->name, NULL, 0, 0, 0);
-               if (error)
-                       return error;
-       }
-
-       /* Return through std_return after this point. */
-
        error = xfs_qm_dqattach(sip, 0);
        if (error)
                goto std_return;
@@ -1953,15 +1861,8 @@ xfs_link(
 
        xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
 
-       /*
-        * Increment vnode ref counts since xfs_trans_commit &
-        * xfs_trans_cancel will both unlock the inodes and
-        * decrement the associated ref counts.
-        */
-       IHOLD(sip);
-       IHOLD(tdp);
-       xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, sip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, tdp, XFS_ILOCK_EXCL);
 
        /*
         * If the source has too many links, we can't make any more to it.
@@ -2014,27 +1915,14 @@ xfs_link(
                goto abort_return;
        }
 
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error)
-               goto std_return;
-
-       /* Fall through to std_return with error = 0. */
-std_return:
-       if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK,
-                               tdp, DM_RIGHT_NULL,
-                               sip, DM_RIGHT_NULL,
-                               target_name->name, NULL, 0, error, 0);
-       }
-       return error;
+       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 
  abort_return:
        cancel_flags |= XFS_TRANS_ABORT;
-       /* FALLTHROUGH */
-
  error_return:
        xfs_trans_cancel(tp, cancel_flags);
-       goto std_return;
+ std_return:
+       return error;
 }
 
 int
@@ -2074,7 +1962,7 @@ xfs_symlink(
        ip = NULL;
        tp = NULL;
 
-       xfs_itrace_entry(dp);
+       trace_xfs_symlink(dp, link_name);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
@@ -2086,17 +1974,6 @@ xfs_symlink(
        if (pathlen >= MAXPATHLEN)      /* total string too long */
                return XFS_ERROR(ENAMETOOLONG);
 
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp,
-                                       DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
-                                       link_name->name,
-                                       (unsigned char *)target_path, 0, 0, 0);
-               if (error)
-                       return error;
-       }
-
-       /* Return through std_return after this point. */
-
        udqp = gdqp = NULL;
        if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
                prid = dp->i_d.di_projid;
@@ -2180,8 +2057,7 @@ xfs_symlink(
         * transaction cancel unlocking dp so don't do it explicitly in the
         * error path.
         */
-       IHOLD(dp);
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
        unlock_dp_on_error = B_FALSE;
 
        /*
@@ -2215,7 +2091,7 @@ xfs_symlink(
                error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
                                  XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
                                  &first_block, resblks, mval, &nmaps,
-                                 &free_list, NULL);
+                                 &free_list);
                if (error) {
                        goto error1;
                }
@@ -2278,21 +2154,8 @@ xfs_symlink(
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
 
-       /* Fall through to std_return with error = 0 or errno from
-        * xfs_trans_commit     */
-std_return:
-       if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTSYMLINK)) {
-               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK,
-                                       dp, DM_RIGHT_NULL,
-                                       error ? NULL : ip,
-                                       DM_RIGHT_NULL, link_name->name,
-                                       (unsigned char *)target_path,
-                                       0, error, 0);
-       }
-
-       if (!error)
-               *ipp = ip;
-       return error;
+       *ipp = ip;
+       return 0;
 
  error2:
        IRELE(ip);
@@ -2306,8 +2169,8 @@ std_return:
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       goto std_return;
+ std_return:
+       return error;
 }
 
 int
@@ -2333,13 +2196,12 @@ xfs_set_dmattrs(
                return error;
        }
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
 
        ip->i_d.di_dmevmask = evmask;
        ip->i_d.di_dmstate  = state;
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       IHOLD(ip);
        error = xfs_trans_commit(tp, 0);
 
        return error;
@@ -2390,7 +2252,7 @@ xfs_alloc_file_space(
        int                     committed;
        int                     error;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_alloc_file_space(ip);
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
@@ -2412,25 +2274,9 @@ xfs_alloc_file_space(
        startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
        allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 
-       /*      Generate a DMAPI event if needed.       */
-       if (alloc_type != 0 && offset < ip->i_size &&
-                       (attr_flags & XFS_ATTR_DMI) == 0  &&
-                       DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) {
-               xfs_off_t           end_dmi_offset;
-
-               end_dmi_offset = offset+len;
-               if (end_dmi_offset > ip->i_size)
-                       end_dmi_offset = ip->i_size;
-               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, offset,
-                                     end_dmi_offset - offset, 0, NULL);
-               if (error)
-                       return error;
-       }
-
        /*
         * Allocate file space until done or until there is an error
         */
-retry:
        while (allocatesize_fsb && !error) {
                xfs_fileoff_t   s, e;
 
@@ -2488,8 +2334,7 @@ retry:
                if (error)
                        goto error1;
 
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * Issue the xfs_bmapi() call to allocate the blocks
@@ -2498,7 +2343,7 @@ retry:
                error = xfs_bmapi(tp, ip, startoffset_fsb,
                                  allocatesize_fsb, bmapi_flag,
                                  &firstfsb, 0, imapp, &nimaps,
-                                 &free_list, NULL);
+                                 &free_list);
                if (error) {
                        goto error0;
                }
@@ -2527,17 +2372,6 @@ retry:
                startoffset_fsb += allocated_fsb;
                allocatesize_fsb -= allocated_fsb;
        }
-dmapi_enospc_check:
-       if (error == ENOSPC && (attr_flags & XFS_ATTR_DMI) == 0 &&
-           DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) {
-               error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE,
-                               ip, DM_RIGHT_NULL,
-                               ip, DM_RIGHT_NULL,
-                               NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */
-               if (error == 0)
-                       goto retry;     /* Maybe DMAPI app. has made space */
-               /* else fall through with error from XFS_SEND_DATA */
-       }
 
        return error;
 
@@ -2548,7 +2382,7 @@ error0:   /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
 error1:        /* Just cancel transaction */
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       goto dmapi_enospc_check;
+       return error;
 }
 
 /*
@@ -2598,7 +2432,7 @@ xfs_zero_remaining_bytes(
                offset_fsb = XFS_B_TO_FSBT(mp, offset);
                nimap = 1;
                error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0,
-                       NULL, 0, &imap, &nimap, NULL, NULL);
+                       NULL, 0, &imap, &nimap, NULL);
                if (error || nimap < 1)
                        break;
                ASSERT(imap.br_blockcount >= 1);
@@ -2661,7 +2495,6 @@ xfs_free_file_space(
 {
        int                     committed;
        int                     done;
-       xfs_off_t               end_dmi_offset;
        xfs_fileoff_t           endoffset_fsb;
        int                     error;
        xfs_fsblock_t           firstfsb;
@@ -2680,7 +2513,7 @@ xfs_free_file_space(
 
        mp = ip->i_mount;
 
-       xfs_itrace_entry(ip);
+       trace_xfs_free_file_space(ip);
 
        error = xfs_qm_dqattach(ip, 0);
        if (error)
@@ -2691,19 +2524,7 @@ xfs_free_file_space(
                return error;
        rt = XFS_IS_REALTIME_INODE(ip);
        startoffset_fsb = XFS_B_TO_FSB(mp, offset);
-       end_dmi_offset = offset + len;
-       endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
-
-       if (offset < ip->i_size && (attr_flags & XFS_ATTR_DMI) == 0 &&
-           DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) {
-               if (end_dmi_offset > ip->i_size)
-                       end_dmi_offset = ip->i_size;
-               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip,
-                               offset, end_dmi_offset - offset,
-                               AT_DELAY_FLAG(attr_flags), NULL);
-               if (error)
-                       return error;
-       }
+       endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
 
        if (attr_flags & XFS_ATTR_NOLOCK)
                need_iolock = 0;
@@ -2731,7 +2552,7 @@ xfs_free_file_space(
        if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
                nimap = 1;
                error = xfs_bmapi(NULL, ip, startoffset_fsb,
-                       1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
+                       1, 0, NULL, 0, &imap, &nimap, NULL);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -2746,7 +2567,7 @@ xfs_free_file_space(
                }
                nimap = 1;
                error = xfs_bmapi(NULL, ip, endoffset_fsb - 1,
-                       1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
+                       1, 0, NULL, 0, &imap, &nimap, NULL);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -2814,8 +2635,7 @@ xfs_free_file_space(
                if (error)
                        goto error1;
 
-               xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-               xfs_trans_ihold(tp, ip);
+               xfs_trans_ijoin(tp, ip);
 
                /*
                 * issue the bunmapi() call to free the blocks
@@ -2823,7 +2643,7 @@ xfs_free_file_space(
                xfs_bmap_init(&free_list, &firstfsb);
                error = xfs_bunmapi(tp, ip, startoffset_fsb,
                                  endoffset_fsb - startoffset_fsb,
-                                 0, 2, &firstfsb, &free_list, NULL, &done);
+                                 0, 2, &firstfsb, &free_list, &done);
                if (error) {
                        goto error0;
                }
@@ -2883,8 +2703,6 @@ xfs_change_file_space(
        xfs_trans_t     *tp;
        struct iattr    iattr;
 
-       xfs_itrace_entry(ip);
-
        if (!S_ISREG(ip->i_d.di_mode))
                return XFS_ERROR(EINVAL);
 
@@ -2985,8 +2803,7 @@ xfs_change_file_space(
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_ihold(tp, ip);
+       xfs_trans_ijoin(tp, ip);
 
        if ((attr_flags & XFS_ATTR_DMI) == 0) {
                ip->i_d.di_mode &= ~S_ISUID;
index 8b1038607831360ed621ddb5542c9f686338758e..b0c1740124365979f9e6e50a0671bf217206bdda 100644 (file)
 #ifndef ASMARM_AMBA_H
 #define ASMARM_AMBA_H
 
+#include <linux/clk.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/resource.h>
 
 #define AMBA_NR_IRQS   2
 
+struct clk;
+
 struct amba_device {
        struct device           dev;
        struct resource         res;
+       struct clk              *pclk;
        u64                     dma_mask;
        unsigned int            periphid;
        unsigned int            irq[AMBA_NR_IRQS];
@@ -59,6 +64,12 @@ struct amba_device *amba_find_device(const char *, struct device *, unsigned int
 int amba_request_regions(struct amba_device *, const char *);
 void amba_release_regions(struct amba_device *);
 
+#define amba_pclk_enable(d)    \
+       (IS_ERR((d)->pclk) ? 0 : clk_enable((d)->pclk))
+
+#define amba_pclk_disable(d)   \
+       do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
+
 #define amba_config(d) (((d)->periphid >> 24) & 0xff)
 #define amba_rev(d)    (((d)->periphid >> 20) & 0x0f)
 #define amba_manf(d)   (((d)->periphid >> 12) & 0xff)
index 7e466fe72025e26fb9fde46fe91202f5768d9a3d..ca84ce70d5d5fca84b7de66533ba06cab54e5298 100644 (file)
  * @ocr_mask: available voltages on the 4 pins from the block, this
  * is ignored if a regulator is used, see the MMC_VDD_* masks in
  * mmc/host.h
- * @translate_vdd: a callback function to translate a MMC_VDD_*
- * mask into a value to be binary or:ed and written into the
- * MMCIPWR register of the block
+ * @vdd_handler: a callback function to translate a MMC_VDD_*
+ * mask into a value to be binary (or set some other custom bits
+ * in MMCIPWR) or:ed and written into the MMCIPWR register of the
+ * block.  May also control external power based on the power_mode.
  * @status: if no GPIO read function was given to the block in
  * gpio_wp (below) this function will be called to determine
  * whether a card is present in the MMC slot or not
@@ -29,7 +30,8 @@
 struct mmci_platform_data {
        unsigned int f_max;
        unsigned int ocr_mask;
-       u32 (*translate_vdd)(struct device *, unsigned int);
+       u32 (*vdd_handler)(struct device *, unsigned int vdd,
+                          unsigned char power_mode);
        unsigned int (*status)(struct device *);
        int     gpio_wp;
        int     gpio_cd;
index 5a5a7fd62490ca34fe27baa952f48de8831d8197..e1b634b635f2a3df5e8a0787c76ea371ae9d8f1a 100644 (file)
 #define UART01x_FR             0x18    /* Flag register (Read only). */
 #define UART010_IIR            0x1C    /* Interrupt indentification register (Read). */
 #define UART010_ICR            0x1C    /* Interrupt clear register (Write). */
+#define ST_UART011_LCRH_RX     0x1C    /* Rx line control register. */
 #define UART01x_ILPR           0x20    /* IrDA low power counter register. */
 #define UART011_IBRD           0x24    /* Integer baud rate divisor register. */
 #define UART011_FBRD           0x28    /* Fractional baud rate divisor register. */
 #define UART011_LCRH           0x2c    /* Line control register. */
+#define ST_UART011_LCRH_TX     0x2c    /* Tx Line control register. */
 #define UART011_CR             0x30    /* Control register. */
 #define UART011_IFLS           0x34    /* Interrupt fifo level select. */
 #define UART011_IMSC           0x38    /* Interrupt mask. */
@@ -84,6 +86,7 @@
 #define UART010_CR_TIE                 0x0020
 #define UART010_CR_RIE                 0x0010
 #define UART010_CR_MSIE                0x0008
+#define ST_UART011_CR_OVSFACT  0x0008  /* Oversampling factor */
 #define UART01x_CR_IIRLP       0x0004  /* SIR low power mode */
 #define UART01x_CR_SIREN       0x0002  /* SIR enable */
 #define UART01x_CR_UARTEN      0x0001  /* UART enable */
index 39e5ff512fbeab16280345eb3e54beb78e8ed0e7..90012b9ddbf3e5f999983bf7d2f6e388a99d25a1 100644 (file)
@@ -49,9 +49,6 @@ typedef struct __user_cap_data_struct {
 } __user *cap_user_data_t;
 
 
-#define XATTR_CAPS_SUFFIX "capability"
-#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
-
 #define VFS_CAP_REVISION_MASK  0xFF000000
 #define VFS_CAP_REVISION_SHIFT 24
 #define VFS_CAP_FLAGS_MASK     ~VFS_CAP_REVISION_MASK
index 75c0fa8813088c31148be71b7cbff77670b6e5d0..4d2c39573f3694cdeef07d83c6f141b4804a5f36 100644 (file)
@@ -153,6 +153,7 @@ struct cred {
 extern void __put_cred(struct cred *);
 extern void exit_creds(struct task_struct *);
 extern int copy_creds(struct task_struct *, unsigned long);
+extern const struct cred *get_task_cred(struct task_struct *);
 extern struct cred *cred_alloc_blank(void);
 extern struct cred *prepare_creds(void);
 extern struct cred *prepare_exec_creds(void);
@@ -273,33 +274,18 @@ static inline void put_cred(const struct cred *_cred)
  * @task: The task to query
  *
  * Access the objective credentials of a task.  The caller must hold the RCU
- * readlock.
+ * readlock or the task must be dead and unable to change its own credentials.
  *
- * The caller must make sure task doesn't go away, either by holding a ref on
- * task or by holding tasklist_lock to prevent it from being unlinked.
+ * The result of this function should not be passed directly to get_cred();
+ * rather get_task_cred() should be used instead.
  */
-#define __task_cred(task) \
-       ((const struct cred *)(rcu_dereference_check((task)->real_cred, rcu_read_lock_held() || lockdep_tasklist_lock_is_held())))
-
-/**
- * get_task_cred - Get another task's objective credentials
- * @task: The task to query
- *
- * Get the objective credentials of a task, pinning them so that they can't go
- * away.  Accessing a task's credentials directly is not permitted.
- *
- * The caller must make sure task doesn't go away, either by holding a ref on
- * task or by holding tasklist_lock to prevent it from being unlinked.
- */
-#define get_task_cred(task)                            \
-({                                                     \
-       struct cred *__cred;                            \
-       rcu_read_lock();                                \
-       __cred = (struct cred *) __task_cred((task));   \
-       get_cred(__cred);                               \
-       rcu_read_unlock();                              \
-       __cred;                                         \
-})
+#define __task_cred(task)                                              \
+       ({                                                              \
+               const struct task_struct *__t = (task);                 \
+               rcu_dereference_check(__t->real_cred,                   \
+                                     rcu_read_lock_held() ||           \
+                                     task_is_dead(__t));               \
+       })
 
 /**
  * get_current_cred - Get the current task's subjective credentials
index b6cb5425cde398a0def4d0d7b8e93d1d713569f4..493a2bf85f62b9fb57ee79b8f55ed7d8398d3c1b 100644 (file)
@@ -62,6 +62,7 @@ typedef enum fe_caps {
        FE_CAN_8VSB                     = 0x200000,
        FE_CAN_16VSB                    = 0x400000,
        FE_HAS_EXTENDED_CAPS            = 0x800000,   /* We need more bitspace for newer APIs, indicate this. */
+       FE_CAN_TURBO_FEC                = 0x8000000,  /* frontend supports "turbo fec modulation" */
        FE_CAN_2G_MODULATION            = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
        FE_NEEDS_BENDING                = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
        FE_CAN_RECOVER                  = 0x40000000, /* frontend can recover from a cable unplug automatically */
index 540b0583d9fb1b7a3dc7b0584e56dc2af66af48a..5a7546c12688df9f5f9fda9b91fb5bafcb94c42c 100644 (file)
@@ -24,6 +24,6 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 1
+#define DVB_API_VERSION_MINOR 2
 
 #endif /*_DVBVERSION_H_*/
index 68ca1b0491af42051bb6e93f424b3741c1ed7278..e5106e49bd2ccce31cad95a2fe5f30efb5233dae 100644 (file)
@@ -53,6 +53,7 @@ struct inodes_stat_t {
 #define MAY_APPEND 8
 #define MAY_ACCESS 16
 #define MAY_OPEN 32
+#define MAY_CHDIR 64
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
@@ -415,7 +416,8 @@ struct buffer_head;
 typedef int (get_block_t)(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create);
 typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
-                       ssize_t bytes, void *private);
+                       ssize_t bytes, void *private, int ret,
+                       bool is_async);
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
index 02c9af374741835efb1feaa1cd0c4f7bcc7e80dd..269181b8f623d50a689f8091557187245e8783e8 100644 (file)
 
 #define ADP5588_KEYMAPSIZE     80
 
+#define GPI_PIN_ROW0 97
+#define GPI_PIN_ROW1 98
+#define GPI_PIN_ROW2 99
+#define GPI_PIN_ROW3 100
+#define GPI_PIN_ROW4 101
+#define GPI_PIN_ROW5 102
+#define GPI_PIN_ROW6 103
+#define GPI_PIN_ROW7 104
+#define GPI_PIN_COL0 105
+#define GPI_PIN_COL1 106
+#define GPI_PIN_COL2 107
+#define GPI_PIN_COL3 108
+#define GPI_PIN_COL4 109
+#define GPI_PIN_COL5 110
+#define GPI_PIN_COL6 111
+#define GPI_PIN_COL7 112
+#define GPI_PIN_COL8 113
+#define GPI_PIN_COL9 114
+
+#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
+#define GPI_PIN_ROW_END GPI_PIN_ROW7
+#define GPI_PIN_COL_BASE GPI_PIN_COL0
+#define GPI_PIN_COL_END GPI_PIN_COL9
+
+#define GPI_PIN_BASE GPI_PIN_ROW_BASE
+#define GPI_PIN_END GPI_PIN_COL_END
+
+#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
+
+struct adp5588_gpi_map {
+       unsigned short pin;
+       unsigned short sw_evt;
+};
+
 struct adp5588_kpad_platform_data {
        int rows;                       /* Number of rows */
        int cols;                       /* Number of columns */
@@ -87,6 +121,9 @@ struct adp5588_kpad_platform_data {
        unsigned en_keylock:1;          /* Enable Key Lock feature */
        unsigned short unlock_key1;     /* Unlock Key 1 */
        unsigned short unlock_key2;     /* Unlock Key 2 */
+       const struct adp5588_gpi_map *gpimap;
+       unsigned short gpimapsize;
+       const struct adp5588_gpio_platform_data *gpio_data;
 };
 
 struct adp5588_gpio_platform_data {
diff --git a/include/linux/i2c/mcs.h b/include/linux/i2c/mcs.h
new file mode 100644 (file)
index 0000000..725ae7c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 - 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: 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 version.
+ *
+ */
+
+#ifndef __LINUX_MCS_H
+#define __LINUX_MCS_H
+
+#define MCS_KEY_MAP(v, c)      ((((v) & 0xff) << 16) | ((c) & 0xffff))
+#define MCS_KEY_VAL(v)         (((v) >> 16) & 0xff)
+#define MCS_KEY_CODE(v)                ((v) & 0xffff)
+
+struct mcs_platform_data {
+       void (*cfg_pin)(void);
+
+       /* touchscreen */
+       unsigned int x_size;
+       unsigned int y_size;
+
+       /* touchkey */
+       const u32 *keymap;
+       unsigned int keymap_size;
+       unsigned int key_maxval;
+       bool no_autorepeat;
+};
+
+#endif /* __LINUX_MCS_H */
diff --git a/include/linux/i2c/mcs5000_ts.h b/include/linux/i2c/mcs5000_ts.h
deleted file mode 100644 (file)
index 5a117b5..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * mcs5000_ts.h
- *
- * Copyright (C) 2009 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_MCS5000_TS_H
-#define __LINUX_MCS5000_TS_H
-
-/* platform data for the MELFAS MCS-5000 touchscreen driver */
-struct mcs5000_ts_platform_data {
-       void (*cfg_pin)(void);
-       int x_size;
-       int y_size;
-};
-
-#endif /* __LINUX_MCS5000_TS_H */
diff --git a/include/linux/i2c/qt602240_ts.h b/include/linux/i2c/qt602240_ts.h
new file mode 100644 (file)
index 0000000..c5033e1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 6fcc9101beeb3e907b9b4c030fef7db9b7f9e334..339d043ccb535c427cf8680be0d8a5aeb3274382 100644 (file)
@@ -691,9 +691,12 @@ struct input_absinfo {
 #define ABS_TILT_X             0x1a
 #define ABS_TILT_Y             0x1b
 #define ABS_TOOL_WIDTH         0x1c
+
 #define ABS_VOLUME             0x20
+
 #define ABS_MISC               0x28
 
+#define ABS_MT_SLOT            0x2f    /* MT slot being modified */
 #define ABS_MT_TOUCH_MAJOR     0x30    /* Major axis of touching ellipse */
 #define ABS_MT_TOUCH_MINOR     0x31    /* Minor axis (omit if circular) */
 #define ABS_MT_WIDTH_MAJOR     0x32    /* Major axis of approaching ellipse */
@@ -706,6 +709,12 @@ struct input_absinfo {
 #define ABS_MT_TRACKING_ID     0x39    /* Unique ID of initiated contact */
 #define ABS_MT_PRESSURE                0x3a    /* Pressure on contact area */
 
+#ifdef __KERNEL__
+/* Implementation details, userspace should not care about these */
+#define ABS_MT_FIRST           ABS_MT_TOUCH_MAJOR
+#define ABS_MT_LAST            ABS_MT_PRESSURE
+#endif
+
 #define ABS_MAX                        0x3f
 #define ABS_CNT                        (ABS_MAX+1)
 
@@ -1047,6 +1056,14 @@ struct ff_effect {
 #include <linux/timer.h>
 #include <linux/mod_devicetable.h>
 
+/**
+ * struct input_mt_slot - represents the state of an input MT slot
+ * @abs: holds current values of ABS_MT axes for this slot
+ */
+struct input_mt_slot {
+       int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
+};
+
 /**
  * struct input_dev - represents an input device
  * @name: name of the device
@@ -1063,6 +1080,10 @@ struct ff_effect {
  * @sndbit: bitmap of sound effects supported by the device
  * @ffbit: bitmap of force feedback effects supported by the device
  * @swbit: bitmap of switches present on the device
+ * @hint_events_per_packet: average number of events generated by the
+ *     device in a packet (between EV_SYN/SYN_REPORT events). Used by
+ *     event handlers to estimate size of the buffer needed to hold
+ *     events.
  * @keycodemax: size of keycode table
  * @keycodesize: size of elements in keycode table
  * @keycode: map of scancodes to keycodes for this device
@@ -1078,9 +1099,12 @@ struct ff_effect {
  * @repeat_key: stores key code of the last key pressed; used to implement
  *     software autorepeat
  * @timer: timer for software autorepeat
- * @sync: set to 1 when there were no new events since last EV_SYNC
  * @abs: current values for reports from absolute axes
  * @rep: current values for autorepeat parameters (delay, rate)
+ * @mt: pointer to array of struct input_mt_slot holding current values
+ *     of tracked contacts
+ * @mtsize: number of MT slots the device uses
+ * @slot: MT slot currently being transmitted
  * @key: reflects current state of device's keys/buttons
  * @led: reflects current state of device's LEDs
  * @snd: reflects current state of sound effects
@@ -1119,6 +1143,7 @@ struct ff_effect {
  *     last user closes the device
  * @going_away: marks devices that are in a middle of unregistering and
  *     causes input_open_device*() fail with -ENODEV.
+ * @sync: set to %true when there were no new events since last EV_SYN
  * @dev: driver model's view of this device
  * @h_list: list of input handles associated with the device. When
  *     accessing the list dev->mutex must be held
@@ -1140,6 +1165,8 @@ struct input_dev {
        unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
        unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
 
+       unsigned int hint_events_per_packet;
+
        unsigned int keycodemax;
        unsigned int keycodesize;
        void *keycode;
@@ -1153,11 +1180,13 @@ struct input_dev {
        unsigned int repeat_key;
        struct timer_list timer;
 
-       int sync;
-
        int abs[ABS_CNT];
        int rep[REP_MAX + 1];
 
+       struct input_mt_slot *mt;
+       int mtsize;
+       int slot;
+
        unsigned long key[BITS_TO_LONGS(KEY_CNT)];
        unsigned long led[BITS_TO_LONGS(LED_CNT)];
        unsigned long snd[BITS_TO_LONGS(SND_CNT)];
@@ -1182,6 +1211,8 @@ struct input_dev {
        unsigned int users;
        bool going_away;
 
+       bool sync;
+
        struct device dev;
 
        struct list_head        h_list;
@@ -1406,8 +1437,28 @@ static inline void input_mt_sync(struct input_dev *dev)
        input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
 }
 
+static inline void input_mt_slot(struct input_dev *dev, int slot)
+{
+       input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
+}
+
 void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
 
+/**
+ * input_set_events_per_packet - tell handlers about the driver event rate
+ * @dev: the input device used by the driver
+ * @n_events: the average number of events between calls to input_sync()
+ *
+ * If the event rate sent from a device is unusually large, use this
+ * function to set the expected event rate. This will allow handlers
+ * to set up an appropriate buffer size for the event stream, in order
+ * to minimize information loss.
+ */
+static inline void input_set_events_per_packet(struct input_dev *dev, int n_events)
+{
+       dev->hint_events_per_packet = n_events;
+}
+
 static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
 {
        dev->absmin[axis] = min;
@@ -1485,5 +1536,8 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
 int input_ff_create_memless(struct input_dev *dev, void *data,
                int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
 
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots);
+void input_mt_destroy_slots(struct input_dev *dev);
+
 #endif
 #endif
diff --git a/include/linux/input/adxl34x.h b/include/linux/input/adxl34x.h
new file mode 100644 (file)
index 0000000..df00d99
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * include/linux/input/adxl34x.h
+ *
+ * Digital Accelerometer characteristics are highly application specific
+ * and may vary between boards and models. The platform_data for the
+ * device's "struct device" holds this information.
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __LINUX_INPUT_ADXL34X_H__
+#define __LINUX_INPUT_ADXL34X_H__
+
+struct adxl34x_platform_data {
+
+       /*
+        * X,Y,Z Axis Offset:
+        * offer user offset adjustments in twoscompliment
+        * form with a scale factor of 15.6 mg/LSB (i.e. 0x7F = +2 g)
+        */
+
+       s8 x_axis_offset;
+       s8 y_axis_offset;
+       s8 z_axis_offset;
+
+       /*
+        * TAP_X/Y/Z Enable: Setting TAP_X, Y, or Z Enable enables X,
+        * Y, or Z participation in Tap detection. A '0' excludes the
+        * selected axis from participation in Tap detection.
+        * Setting the SUPPRESS bit suppresses Double Tap detection if
+        * acceleration greater than tap_threshold is present between
+        * taps.
+        */
+
+#define ADXL_SUPPRESS  (1 << 3)
+#define ADXL_TAP_X_EN  (1 << 2)
+#define ADXL_TAP_Y_EN  (1 << 1)
+#define ADXL_TAP_Z_EN  (1 << 0)
+
+       u8 tap_axis_control;
+
+       /*
+        * tap_threshold:
+        * holds the threshold value for tap detection/interrupts.
+        * The data format is unsigned. The scale factor is 62.5 mg/LSB
+        * (i.e. 0xFF = +16 g). A zero value may result in undesirable
+        * behavior if Tap/Double Tap is enabled.
+        */
+
+       u8 tap_threshold;
+
+       /*
+        * tap_duration:
+        * is an unsigned time value representing the maximum
+        * time that an event must be above the tap_threshold threshold
+        * to qualify as a tap event. The scale factor is 625 us/LSB. A zero
+        * value will prevent Tap/Double Tap functions from working.
+        */
+
+       u8 tap_duration;
+
+       /*
+        * tap_latency:
+        * is an unsigned time value representing the wait time
+        * from the detection of a tap event to the opening of the time
+        * window tap_window for a possible second tap event. The scale
+        * factor is 1.25 ms/LSB. A zero value will disable the Double Tap
+        * function.
+        */
+
+       u8 tap_latency;
+
+       /*
+        * tap_window:
+        * is an unsigned time value representing the amount
+        * of time after the expiration of tap_latency during which a second
+        * tap can begin. The scale factor is 1.25 ms/LSB. A zero value will
+        * disable the Double Tap function.
+        */
+
+       u8 tap_window;
+
+       /*
+        * act_axis_control:
+        * X/Y/Z Enable: A '1' enables X, Y, or Z participation in activity
+        * or inactivity detection. A '0' excludes the selected axis from
+        * participation. If all of the axes are excluded, the function is
+        * disabled.
+        * AC/DC: A '0' = DC coupled operation and a '1' = AC coupled
+        * operation. In DC coupled operation, the current acceleration is
+        * compared with activity_threshold and inactivity_threshold directly
+        * to determine whether activity or inactivity is detected. In AC
+        * coupled operation for activity detection, the acceleration value
+        * at the start of activity detection is taken as a reference value.
+        * New samples of acceleration are then compared to this
+        * reference value and if the magnitude of the difference exceeds
+        * activity_threshold the device will trigger an activity interrupt. In
+        * AC coupled operation for inactivity detection, a reference value
+        * is used again for comparison and is updated whenever the
+        * device exceeds the inactivity threshold. Once the reference
+        * value is selected, the device compares the magnitude of the
+        * difference between the reference value and the current
+        * acceleration with inactivity_threshold. If the difference is below
+        * inactivity_threshold for a total of inactivity_time, the device is
+        * considered inactive and the inactivity interrupt is triggered.
+        */
+
+#define ADXL_ACT_ACDC          (1 << 7)
+#define ADXL_ACT_X_EN          (1 << 6)
+#define ADXL_ACT_Y_EN          (1 << 5)
+#define ADXL_ACT_Z_EN          (1 << 4)
+#define ADXL_INACT_ACDC                (1 << 3)
+#define ADXL_INACT_X_EN                (1 << 2)
+#define ADXL_INACT_Y_EN                (1 << 1)
+#define ADXL_INACT_Z_EN                (1 << 0)
+
+       u8 act_axis_control;
+
+       /*
+        * activity_threshold:
+        * holds the threshold value for activity detection.
+        * The data format is unsigned. The scale factor is
+        * 62.5 mg/LSB. A zero value may result in undesirable behavior if
+        * Activity interrupt is enabled.
+        */
+
+       u8 activity_threshold;
+
+       /*
+        * inactivity_threshold:
+        * holds the threshold value for inactivity
+        * detection. The data format is unsigned. The scale
+        * factor is 62.5 mg/LSB. A zero value may result in undesirable
+        * behavior if Inactivity interrupt is enabled.
+        */
+
+       u8 inactivity_threshold;
+
+       /*
+        * inactivity_time:
+        * is an unsigned time value representing the
+        * amount of time that acceleration must be below the value in
+        * inactivity_threshold for inactivity to be declared. The scale factor
+        * is 1 second/LSB. Unlike the other interrupt functions, which
+        * operate on unfiltered data, the inactivity function operates on the
+        * filtered output data. At least one output sample must be
+        * generated for the inactivity interrupt to be triggered. This will
+        * result in the function appearing un-responsive if the
+        * inactivity_time register is set with a value less than the time
+        * constant of the Output Data Rate. A zero value will result in an
+        * interrupt when the output data is below inactivity_threshold.
+        */
+
+       u8 inactivity_time;
+
+       /*
+        * free_fall_threshold:
+        * holds the threshold value for Free-Fall detection.
+        * The data format is unsigned. The root-sum-square(RSS) value
+        * of all axes is calculated and compared to the value in
+        * free_fall_threshold to determine if a free fall event may be
+        * occurring.  The scale factor is 62.5 mg/LSB. A zero value may
+        * result in undesirable behavior if Free-Fall interrupt is
+        * enabled. Values between 300 and 600 mg (0x05 to 0x09) are
+        * recommended.
+        */
+
+       u8 free_fall_threshold;
+
+       /*
+        * free_fall_time:
+        * is an unsigned time value representing the minimum
+        * time that the RSS value of all axes must be less than
+        * free_fall_threshold to generate a Free-Fall interrupt. The
+        * scale factor is 5 ms/LSB. A zero value may result in
+        * undesirable behavior if Free-Fall interrupt is enabled.
+        * Values between 100 to 350 ms (0x14 to 0x46) are recommended.
+        */
+
+       u8 free_fall_time;
+
+       /*
+        * data_rate:
+        * Selects device bandwidth and output data rate.
+        * RATE = 3200 Hz / (2^(15 - x)). Default value is 0x0A, or 100 Hz
+        * Output Data Rate. An Output Data Rate should be selected that
+        * is appropriate for the communication protocol and frequency
+        * selected. Selecting too high of an Output Data Rate with a low
+        * communication speed will result in samples being discarded.
+        */
+
+       u8 data_rate;
+
+       /*
+        * data_range:
+        * FULL_RES: When this bit is set with the device is
+        * in Full-Resolution Mode, where the output resolution increases
+        * with RANGE to maintain a 4 mg/LSB scale factor. When this
+        * bit is cleared the device is in 10-bit Mode and RANGE determine the
+        * maximum g-Range and scale factor.
+        */
+
+#define ADXL_FULL_RES          (1 << 3)
+#define ADXL_RANGE_PM_2g       0
+#define ADXL_RANGE_PM_4g       1
+#define ADXL_RANGE_PM_8g       2
+#define ADXL_RANGE_PM_16g      3
+
+       u8 data_range;
+
+       /*
+        * low_power_mode:
+        * A '0' = Normal operation and a '1' = Reduced
+        * power operation with somewhat higher noise.
+        */
+
+       u8 low_power_mode;
+
+       /*
+        * power_mode:
+        * LINK: A '1' with both the activity and inactivity functions
+        * enabled will delay the start of the activity function until
+        * inactivity is detected. Once activity is detected, inactivity
+        * detection will begin and prevent the detection of activity. This
+        * bit serially links the activity and inactivity functions. When '0'
+        * the inactivity and activity functions are concurrent. Additional
+        * information can be found in the Application section under Link
+        * Mode.
+        * AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
+        * when inactivity (acceleration has been below inactivity_threshold
+        * for at least inactivity_time) is detected and the LINK bit is set.
+        * A '0' disables automatic switching to Sleep Mode. See SLEEP
+        * for further description.
+        */
+
+#define ADXL_LINK      (1 << 5)
+#define ADXL_AUTO_SLEEP        (1 << 4)
+
+       u8 power_mode;
+
+       /*
+        * fifo_mode:
+        * BYPASS The FIFO is bypassed
+        * FIFO   FIFO collects up to 32 values then stops collecting data
+        * STREAM FIFO holds the last 32 data values. Once full, the FIFO's
+        *        oldest data is lost as it is replaced with newer data
+        *
+        * DEFAULT should be ADXL_FIFO_STREAM
+        */
+
+#define ADXL_FIFO_BYPASS       0
+#define ADXL_FIFO_FIFO         1
+#define ADXL_FIFO_STREAM       2
+
+       u8 fifo_mode;
+
+       /*
+        * watermark:
+        * The Watermark feature can be used to reduce the interrupt load
+        * of the system. The FIFO fills up to the value stored in watermark
+        * [1..32] and then generates an interrupt.
+        * A '0' disables the watermark feature.
+        */
+
+       u8 watermark;
+
+       u32 ev_type;    /* EV_ABS or EV_REL */
+
+       u32 ev_code_x;  /* ABS_X,Y,Z or REL_X,Y,Z */
+       u32 ev_code_y;  /* ABS_X,Y,Z or REL_X,Y,Z */
+       u32 ev_code_z;  /* ABS_X,Y,Z or REL_X,Y,Z */
+
+       /*
+        * A valid BTN or KEY Code; use tap_axis_control to disable
+        * event reporting
+        */
+
+       u32 ev_code_tap[3];     /* EV_KEY {X-Axis, Y-Axis, Z-Axis} */
+
+       /*
+        * A valid BTN or KEY Code for Free-Fall or Activity enables
+        * input event reporting. A '0' disables the Free-Fall or
+        * Activity reporting.
+        */
+
+       u32 ev_code_ff; /* EV_KEY */
+       u32 ev_code_act_inactivity;     /* EV_KEY */
+
+       /*
+        * Use ADXL34x INT2 instead of INT1
+        */
+       u8 use_int2;
+
+       /*
+        * ADXL346 only ORIENTATION SENSING feature
+        * The orientation function of the ADXL346 reports both 2-D and
+        * 3-D orientation concurrently.
+        */
+
+#define ADXL_EN_ORIENTATION_2D         1
+#define ADXL_EN_ORIENTATION_3D         2
+#define ADXL_EN_ORIENTATION_2D_3D      3
+
+       u8 orientation_enable;
+
+       /*
+        * The width of the deadzone region between two or more
+        * orientation positions is determined by setting the Deadzone
+        * value. The deadzone region size can be specified with a
+        * resolution of 3.6deg. The deadzone angle represents the total
+        * angle where the orientation is considered invalid.
+        */
+
+#define ADXL_DEADZONE_ANGLE_0p0                0       /* !!!0.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_3p6                1       /* 3.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_7p2                2       /* 7.2 [deg] */
+#define ADXL_DEADZONE_ANGLE_10p8       3       /* 10.8 [deg] */
+#define ADXL_DEADZONE_ANGLE_14p4       4       /* 14.4 [deg] */
+#define ADXL_DEADZONE_ANGLE_18p0       5       /* 18.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_21p6       6       /* 21.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_25p2       7       /* 25.2 [deg] */
+
+       u8 deadzone_angle;
+
+       /*
+        * To eliminate most human motion such as walking or shaking,
+        * a Divisor value should be selected to effectively limit the
+        * orientation bandwidth. Set the depth of the filter used to
+        * low-pass filter the measured acceleration for stable
+        * orientation sensing
+        */
+
+#define ADXL_LP_FILTER_DIVISOR_2       0
+#define ADXL_LP_FILTER_DIVISOR_4       1
+#define ADXL_LP_FILTER_DIVISOR_8       2
+#define ADXL_LP_FILTER_DIVISOR_16      3
+#define ADXL_LP_FILTER_DIVISOR_32      4
+#define ADXL_LP_FILTER_DIVISOR_64      5
+#define ADXL_LP_FILTER_DIVISOR_128     6
+#define ADXL_LP_FILTER_DIVISOR_256     7
+
+       u8 divisor_length;
+
+       u32 ev_codes_orient_2d[4];      /* EV_KEY {+X, -X, +Y, -Y} */
+       u32 ev_codes_orient_3d[6];      /* EV_KEY {+Z, +Y, +X, -X, -Y, -Z} */
+};
+#endif
diff --git a/include/linux/input/cy8ctmg110_pdata.h b/include/linux/input/cy8ctmg110_pdata.h
new file mode 100644 (file)
index 0000000..09522cb
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _LINUX_CY8CTMG110_PDATA_H
+#define _LINUX_CY8CTMG110_PDATA_H
+
+struct cy8ctmg110_pdata
+{
+       int reset_pin;          /* Reset pin is wired to this GPIO (optional) */
+       int irq_pin;            /* IRQ pin is wired to this GPIO */
+};
+
+#endif
index c964cd7f436a4ecf63d6f2080d280734f5a2a4ca..80352ad6581a70f6ea699048f055a528b111ef18 100644 (file)
@@ -41,6 +41,9 @@ struct matrix_keymap_data {
  * @col_scan_delay_us: delay, measured in microseconds, that is
  *     needed before we can keypad after activating column gpio
  * @debounce_ms: debounce interval in milliseconds
+ * @clustered_irq: may be specified if interrupts of all row/column GPIOs
+ *     are bundled to one single irq
+ * @clustered_irq_flags: flags that are needed for the clustered irq
  * @active_low: gpio polarity
  * @wakeup: controls whether the device should be set up as wakeup
  *     source
@@ -63,6 +66,9 @@ struct matrix_keypad_platform_data {
        /* key debounce interval in milli-second */
        unsigned int    debounce_ms;
 
+       unsigned int    clustered_irq;
+       unsigned int    clustered_irq_flags;
+
        bool            active_low;
        bool            wakeup;
        bool            no_autorepeat;
index 6907251d52003c64434d33d1c4f9f691e6fb1419..112a55033352bbaaf79e045f9367edd3f45f5b1e 100644 (file)
@@ -90,9 +90,41 @@ struct common_audit_data {
                        u32 requested;
                        u32 audited;
                        u32 denied;
+                       /*
+                        * auditdeny is a bit tricky and unintuitive.  See the
+                        * comments in avc.c for it's meaning and usage.
+                        */
+                       u32 auditdeny;
                        struct av_decision *avd;
                        int result;
                } selinux_audit_data;
+#endif
+#ifdef CONFIG_SECURITY_APPARMOR
+               struct {
+                       int error;
+                       int op;
+                       int type;
+                       void *profile;
+                       const char *name;
+                       const char *info;
+                       union {
+                               void *target;
+                               struct {
+                                       long pos;
+                                       void *target;
+                               } iface;
+                               struct {
+                                       int rlim;
+                                       unsigned long max;
+                               } rlim;
+                               struct {
+                                       const char *target;
+                                       u32 request;
+                                       u32 denied;
+                                       uid_t ouid;
+                               } fs;
+                       };
+               } apparmor_audit_data;
 #endif
        };
        /* these callback will be implemented by a specific LSM */
diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h
new file mode 100644 (file)
index 0000000..2ed4fb8
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _MARVELL_PHY_H
+#define _MARVELL_PHY_H
+
+/* Mask used for ID comparisons */
+#define MARVELL_PHY_ID_MASK            0xfffffff0
+
+/* Known PHY IDs */
+#define MARVELL_PHY_ID_88E1101         0x01410c60
+#define MARVELL_PHY_ID_88E1112         0x01410c90
+#define MARVELL_PHY_ID_88E1111         0x01410cc0
+#define MARVELL_PHY_ID_88E1118         0x01410e10
+#define MARVELL_PHY_ID_88E1121R                0x01410cb0
+#define MARVELL_PHY_ID_88E1145         0x01410cd0
+#define MARVELL_PHY_ID_88E1240         0x01410e30
+
+/* struct phy_device dev_flags definitions */
+#define MARVELL_PHY_M1145_FLAGS_RESISTANCE     0x00000001
+#define MARVELL_PHY_M1118_DNS323_LEDS          0x00000002
+
+#endif /* _MARVELL_PHY_H */
index 77c2ae53431cccbdccf7932a84cd032e0b7e914c..bad4d121b16efa42fa161b2b525d1e73f42b8a71 100644 (file)
@@ -493,8 +493,15 @@ extern int nfs_wb_all(struct inode *inode);
 extern int nfs_wb_page(struct inode *inode, struct page* page);
 extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+extern int  nfs_commit_inode(struct inode *, int);
 extern struct nfs_write_data *nfs_commitdata_alloc(void);
 extern void nfs_commit_free(struct nfs_write_data *wdata);
+#else
+static inline int
+nfs_commit_inode(struct inode *inode, int how)
+{
+       return 0;
+}
 #endif
 
 static inline int
index 9bdd91486b49d94c42e9ac00efd29e1b282a53b5..7e4cd616bcb57c0e51358073873502c9c417c3ef 100644 (file)
@@ -253,7 +253,7 @@ struct omapfb_platform_data {
 /* in arch/arm/plat-omap/fb.c */
 extern void omapfb_set_platform_data(struct omapfb_platform_data *data);
 extern void omapfb_set_ctrl_platform_data(void *pdata);
-extern void omapfb_reserve_sdram(void);
+extern void omapfb_reserve_sdram_memblock(void);
 
 #endif
 
index 747fcaedddb70d6cb0a49b43c0d2f2a6f23a693f..0478888c6899d3c59a1649d38dfdd58030f14918 100644 (file)
@@ -214,6 +214,7 @@ extern char ___assert_task_state[1 - 2*!!(
 
 #define task_is_traced(task)   ((task->state & __TASK_TRACED) != 0)
 #define task_is_stopped(task)  ((task->state & __TASK_STOPPED) != 0)
+#define task_is_dead(task)     ((task)->exit_state != 0)
 #define task_is_stopped_or_traced(task)        \
                        ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0)
 #define task_contributes_to_load(task) \
index 0c8819170463624c57f7c968771727eed1038691..723a93df756a1151d3344981bdf88756668e8456 100644 (file)
@@ -470,8 +470,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  * @path_truncate:
  *     Check permission before truncating a file.
  *     @path contains the path structure for the file.
- *     @length is the new length of the file.
- *     @time_attrs is the flags passed to do_truncate().
  *     Return 0 if permission is granted.
  * @inode_getattr:
  *     Check permission before obtaining file attributes.
@@ -1412,8 +1410,7 @@ struct security_operations {
        int (*path_rmdir) (struct path *dir, struct dentry *dentry);
        int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
                           unsigned int dev);
-       int (*path_truncate) (struct path *path, loff_t length,
-                             unsigned int time_attrs);
+       int (*path_truncate) (struct path *path);
        int (*path_symlink) (struct path *dir, struct dentry *dentry,
                             const char *old_name);
        int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
@@ -2806,8 +2803,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
 int security_path_rmdir(struct path *dir, struct dentry *dentry);
 int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
                        unsigned int dev);
-int security_path_truncate(struct path *path, loff_t length,
-                          unsigned int time_attrs);
+int security_path_truncate(struct path *path);
 int security_path_symlink(struct path *dir, struct dentry *dentry,
                          const char *old_name);
 int security_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -2841,8 +2837,7 @@ static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
        return 0;
 }
 
-static inline int security_path_truncate(struct path *path, loff_t length,
-                                        unsigned int time_attrs)
+static inline int security_path_truncate(struct path *path)
 {
        return 0;
 }
index b4ae570d3c9876b090a4446f42a7ccc5c001c189..92bd0839d5b49a414f8cd23fef827403ed965bab 100644 (file)
@@ -48,11 +48,12 @@ struct ads7846_platform_data {
                                         * state if get_pendown_state == NULL
                                         */
        int     (*get_pendown_state)(void);
-       int     (*filter_init)  (struct ads7846_platform_data *pdata,
+       int     (*filter_init)  (const struct ads7846_platform_data *pdata,
                                 void **filter_data);
        int     (*filter)       (void *filter_data, int data_idx, int *val);
        void    (*filter_cleanup)(void *filter_data);
        void    (*wait_for_sync)(void);
        bool    wakeup;
+       unsigned long irq_flags;
 };
 
index 81a4e213c6cf9bd934792d0135836cc9ef8d4d36..8c0e349f4a6cb83f616f1d0046c1db7ab504d531 100644 (file)
@@ -23,6 +23,29 @@ extern int swiotlb_force;
 #define IO_TLB_SHIFT 11
 
 extern void swiotlb_init(int verbose);
+extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
+
+/*
+ * Enumeration for sync targets
+ */
+enum dma_sync_target {
+       SYNC_FOR_CPU = 0,
+       SYNC_FOR_DEVICE = 1,
+};
+extern void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+                                   phys_addr_t phys, size_t size,
+                                   enum dma_data_direction dir);
+
+extern void swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr,
+                                    size_t size, enum dma_data_direction dir);
+
+extern void swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr,
+                                   size_t size, enum dma_data_direction dir,
+                                   enum dma_sync_target target);
+
+/* Accessory functions. */
+extern void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+                          enum dma_data_direction dir);
 
 extern void
 *swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -42,11 +65,11 @@ extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
 
 extern int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-              int direction);
+              enum dma_data_direction dir);
 
 extern void
 swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-                int direction);
+                enum dma_data_direction dir);
 
 extern int
 swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
index be436d9ee4797bb7a5c507bb075e1a55ab1e46af..3b3b95e01f71b338542cd7844811e3e0ee7fc240 100644 (file)
 #define UVC_STATUS_TYPE_CONTROL                                1
 #define UVC_STATUS_TYPE_STREAMING                      2
 
+/* 2.4.3.3. Payload Header Information */
+#define UVC_STREAM_EOH                                 (1 << 7)
+#define UVC_STREAM_ERR                                 (1 << 6)
+#define UVC_STREAM_STI                                 (1 << 5)
+#define UVC_STREAM_RES                                 (1 << 4)
+#define UVC_STREAM_SCR                                 (1 << 3)
+#define UVC_STREAM_PTS                                 (1 << 2)
+#define UVC_STREAM_EOF                                 (1 << 1)
+#define UVC_STREAM_FID                                 (1 << 0)
+
+/* 4.1.2. Control Capabilities */
+#define UVC_CONTROL_CAP_GET                            (1 << 0)
+#define UVC_CONTROL_CAP_SET                            (1 << 1)
+#define UVC_CONTROL_CAP_DISABLED                       (1 << 2)
+#define UVC_CONTROL_CAP_AUTOUPDATE                     (1 << 3)
+#define UVC_CONTROL_CAP_ASYNCHRONOUS                   (1 << 4)
+
+/* ------------------------------------------------------------------------
+ * UVC structures
+ */
+
+/* All UVC descriptors have these 3 fields at the beginning */
+struct uvc_descriptor_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+} __attribute__((packed));
+
+/* 3.7.2. Video Control Interface Header Descriptor */
+struct uvc_header_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u16 bcdUVC;
+       __u16 wTotalLength;
+       __u32 dwClockFrequency;
+       __u8  bInCollection;
+       __u8  baInterfaceNr[];
+} __attribute__((__packed__));
+
+#define UVC_DT_HEADER_SIZE(n)                          (12+(n))
+
+#define UVC_HEADER_DESCRIPTOR(n) \
+       uvc_header_descriptor_##n
+
+#define DECLARE_UVC_HEADER_DESCRIPTOR(n)               \
+struct UVC_HEADER_DESCRIPTOR(n) {                      \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u16 bcdUVC;                                   \
+       __u16 wTotalLength;                             \
+       __u32 dwClockFrequency;                         \
+       __u8  bInCollection;                            \
+       __u8  baInterfaceNr[n];                         \
+} __attribute__ ((packed))
+
+/* 3.7.2.1. Input Terminal Descriptor */
+struct uvc_input_terminal_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bTerminalID;
+       __u16 wTerminalType;
+       __u8  bAssocTerminal;
+       __u8  iTerminal;
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_TERMINAL_SIZE                     8
+
+/* 3.7.2.2. Output Terminal Descriptor */
+struct uvc_output_terminal_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bTerminalID;
+       __u16 wTerminalType;
+       __u8  bAssocTerminal;
+       __u8  bSourceID;
+       __u8  iTerminal;
+} __attribute__((__packed__));
+
+#define UVC_DT_OUTPUT_TERMINAL_SIZE                    9
+
+/* 3.7.2.3. Camera Terminal Descriptor */
+struct uvc_camera_terminal_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bTerminalID;
+       __u16 wTerminalType;
+       __u8  bAssocTerminal;
+       __u8  iTerminal;
+       __u16 wObjectiveFocalLengthMin;
+       __u16 wObjectiveFocalLengthMax;
+       __u16 wOcularFocalLength;
+       __u8  bControlSize;
+       __u8  bmControls[3];
+} __attribute__((__packed__));
+
+#define UVC_DT_CAMERA_TERMINAL_SIZE(n)                 (15+(n))
+
+/* 3.7.2.4. Selector Unit Descriptor */
+struct uvc_selector_unit_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bUnitID;
+       __u8  bNrInPins;
+       __u8  baSourceID[0];
+       __u8  iSelector;
+} __attribute__((__packed__));
+
+#define UVC_DT_SELECTOR_UNIT_SIZE(n)                   (6+(n))
+
+#define UVC_SELECTOR_UNIT_DESCRIPTOR(n)        \
+       uvc_selector_unit_descriptor_##n
+
+#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n)        \
+struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) {               \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u8  bUnitID;                                  \
+       __u8  bNrInPins;                                \
+       __u8  baSourceID[n];                            \
+       __u8  iSelector;                                \
+} __attribute__ ((packed))
+
+/* 3.7.2.5. Processing Unit Descriptor */
+struct uvc_processing_unit_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bUnitID;
+       __u8  bSourceID;
+       __u16 wMaxMultiplier;
+       __u8  bControlSize;
+       __u8  bmControls[2];
+       __u8  iProcessing;
+} __attribute__((__packed__));
+
+#define UVC_DT_PROCESSING_UNIT_SIZE(n)                 (9+(n))
+
+/* 3.7.2.6. Extension Unit Descriptor */
+struct uvc_extension_unit_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bUnitID;
+       __u8  guidExtensionCode[16];
+       __u8  bNumControls;
+       __u8  bNrInPins;
+       __u8  baSourceID[0];
+       __u8  bControlSize;
+       __u8  bmControls[0];
+       __u8  iExtension;
+} __attribute__((__packed__));
+
+#define UVC_DT_EXTENSION_UNIT_SIZE(p, n)               (24+(p)+(n))
+
+#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+       uvc_extension_unit_descriptor_##p_##n
+
+#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n)    \
+struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) {           \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u8  bUnitID;                                  \
+       __u8  guidExtensionCode[16];                    \
+       __u8  bNumControls;                             \
+       __u8  bNrInPins;                                \
+       __u8  baSourceID[p];                            \
+       __u8  bControlSize;                             \
+       __u8  bmControls[n];                            \
+       __u8  iExtension;                               \
+} __attribute__ ((packed))
+
+/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */
+struct uvc_control_endpoint_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u16 wMaxTransferSize;
+} __attribute__((__packed__));
+
+#define UVC_DT_CONTROL_ENDPOINT_SIZE                   5
+
+/* 3.9.2.1. Input Header Descriptor */
+struct uvc_input_header_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bNumFormats;
+       __u16 wTotalLength;
+       __u8  bEndpointAddress;
+       __u8  bmInfo;
+       __u8  bTerminalLink;
+       __u8  bStillCaptureMethod;
+       __u8  bTriggerSupport;
+       __u8  bTriggerUsage;
+       __u8  bControlSize;
+       __u8  bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_HEADER_SIZE(n, p)                 (13+(n*p))
+
+#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+       uvc_input_header_descriptor_##n_##p
+
+#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p)      \
+struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) {             \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u8  bNumFormats;                              \
+       __u16 wTotalLength;                             \
+       __u8  bEndpointAddress;                         \
+       __u8  bmInfo;                                   \
+       __u8  bTerminalLink;                            \
+       __u8  bStillCaptureMethod;                      \
+       __u8  bTriggerSupport;                          \
+       __u8  bTriggerUsage;                            \
+       __u8  bControlSize;                             \
+       __u8  bmaControls[p][n];                        \
+} __attribute__ ((packed))
+
+/* 3.9.2.2. Output Header Descriptor */
+struct uvc_output_header_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bNumFormats;
+       __u16 wTotalLength;
+       __u8  bEndpointAddress;
+       __u8  bTerminalLink;
+       __u8  bControlSize;
+       __u8  bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_DT_OUTPUT_HEADER_SIZE(n, p)                        (9+(n*p))
+
+#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+       uvc_output_header_descriptor_##n_##p
+
+#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p)     \
+struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) {            \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u8  bNumFormats;                              \
+       __u16 wTotalLength;                             \
+       __u8  bEndpointAddress;                         \
+       __u8  bTerminalLink;                            \
+       __u8  bControlSize;                             \
+       __u8  bmaControls[p][n];                        \
+} __attribute__ ((packed))
+
+/* 3.9.2.6. Color matching descriptor */
+struct uvc_color_matching_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bColorPrimaries;
+       __u8  bTransferCharacteristics;
+       __u8  bMatrixCoefficients;
+} __attribute__((__packed__));
+
+#define UVC_DT_COLOR_MATCHING_SIZE                     6
+
+/* 4.3.1.1. Video Probe and Commit Controls */
+struct uvc_streaming_control {
+       __u16 bmHint;
+       __u8  bFormatIndex;
+       __u8  bFrameIndex;
+       __u32 dwFrameInterval;
+       __u16 wKeyFrameRate;
+       __u16 wPFrameRate;
+       __u16 wCompQuality;
+       __u16 wCompWindowSize;
+       __u16 wDelay;
+       __u32 dwMaxVideoFrameSize;
+       __u32 dwMaxPayloadTransferSize;
+       __u32 dwClockFrequency;
+       __u8  bmFramingInfo;
+       __u8  bPreferedVersion;
+       __u8  bMinVersion;
+       __u8  bMaxVersion;
+} __attribute__((__packed__));
+
+/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */
+struct uvc_format_uncompressed {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bFormatIndex;
+       __u8  bNumFrameDescriptors;
+       __u8  guidFormat[16];
+       __u8  bBitsPerPixel;
+       __u8  bDefaultFrameIndex;
+       __u8  bAspectRatioX;
+       __u8  bAspectRatioY;
+       __u8  bmInterfaceFlags;
+       __u8  bCopyProtect;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE                        27
+
+/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */
+struct uvc_frame_uncompressed {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bFrameIndex;
+       __u8  bmCapabilities;
+       __u16 wWidth;
+       __u16 wHeight;
+       __u32 dwMinBitRate;
+       __u32 dwMaxBitRate;
+       __u32 dwMaxVideoFrameBufferSize;
+       __u32 dwDefaultFrameInterval;
+       __u8  bFrameIntervalType;
+       __u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n)              (26+4*(n))
+
+#define UVC_FRAME_UNCOMPRESSED(n) \
+       uvc_frame_uncompressed_##n
+
+#define DECLARE_UVC_FRAME_UNCOMPRESSED(n)              \
+struct UVC_FRAME_UNCOMPRESSED(n) {                     \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u8  bFrameIndex;                              \
+       __u8  bmCapabilities;                           \
+       __u16 wWidth;                                   \
+       __u16 wHeight;                                  \
+       __u32 dwMinBitRate;                             \
+       __u32 dwMaxBitRate;                             \
+       __u32 dwMaxVideoFrameBufferSize;                \
+       __u32 dwDefaultFrameInterval;                   \
+       __u8  bFrameIntervalType;                       \
+       __u32 dwFrameInterval[n];                       \
+} __attribute__ ((packed))
+
+/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */
+struct uvc_format_mjpeg {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bFormatIndex;
+       __u8  bNumFrameDescriptors;
+       __u8  bmFlags;
+       __u8  bDefaultFrameIndex;
+       __u8  bAspectRatioX;
+       __u8  bAspectRatioY;
+       __u8  bmInterfaceFlags;
+       __u8  bCopyProtect;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_MJPEG_SIZE                       11
+
+/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
+struct uvc_frame_mjpeg {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDescriptorSubType;
+       __u8  bFrameIndex;
+       __u8  bmCapabilities;
+       __u16 wWidth;
+       __u16 wHeight;
+       __u32 dwMinBitRate;
+       __u32 dwMaxBitRate;
+       __u32 dwMaxVideoFrameBufferSize;
+       __u32 dwDefaultFrameInterval;
+       __u8  bFrameIntervalType;
+       __u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_MJPEG_SIZE(n)                     (26+4*(n))
+
+#define UVC_FRAME_MJPEG(n) \
+       uvc_frame_mjpeg_##n
+
+#define DECLARE_UVC_FRAME_MJPEG(n)                     \
+struct UVC_FRAME_MJPEG(n) {                            \
+       __u8  bLength;                                  \
+       __u8  bDescriptorType;                          \
+       __u8  bDescriptorSubType;                       \
+       __u8  bFrameIndex;                              \
+       __u8  bmCapabilities;                           \
+       __u16 wWidth;                                   \
+       __u16 wHeight;                                  \
+       __u32 dwMinBitRate;                             \
+       __u32 dwMaxBitRate;                             \
+       __u32 dwMaxVideoFrameBufferSize;                \
+       __u32 dwDefaultFrameInterval;                   \
+       __u8  bFrameIntervalType;                       \
+       __u32 dwFrameInterval[n];                       \
+} __attribute__ ((packed))
+
 #endif /* __LINUX_USB_VIDEO_H */
 
index 5cf11765146b11ce43017e702832b4746c7ed87b..395c38a47adbbe4317cc57a44bf99b9daf08d5d9 100644 (file)
@@ -4,6 +4,7 @@
  * compatible drivers/servers. */
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
+#include <linux/types.h>
 
 /* The feature bitmap for virtio 9P */
 
index 0cfa1e9c4cc152239895304d67c6d1500cff7044..f1e5bde4b35acbab2a0a5a525d59dde6e017cc61 100644 (file)
 #define XATTR_USER_PREFIX "user."
 #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
 
+/* Security namespace */
+#define XATTR_SELINUX_SUFFIX "selinux"
+#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_SMACK_IPIN "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+#define XATTR_NAME_SMACKIPIN   XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
+#define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+
+#define XATTR_CAPS_SUFFIX "capability"
+#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+
 struct inode;
 struct dentry;
 
index ad1303f20e002d0484a056d432ca24d11a41e2f8..513e60dd101018f265622521fde93606aa8dbd12 100644 (file)
@@ -47,15 +47,21 @@ enum rc_driver_type {
  *     is opened.
  * @close: callback to allow drivers to disable polling/irq when IR input device
  *     is opened.
+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
+ * @s_tx_carrier: set transmit carrier frequency
+ * @tx_ir: transmit IR
  */
 struct ir_dev_props {
        enum rc_driver_type     driver_type;
        unsigned long           allowed_protos;
        u32                     scanmask;
-       void                    *priv;
+       void                    *priv;
        int                     (*change_protocol)(void *priv, u64 ir_type);
        int                     (*open)(void *priv);
        void                    (*close)(void *priv);
+       int                     (*s_tx_mask)(void *priv, u32 mask);
+       int                     (*s_tx_carrier)(void *priv, u32 carrier);
+       int                     (*tx_ir)(void *priv, int *txbuf, u32 n);
 };
 
 struct ir_input_dev {
index 0506e45c9a4f787a3b082777491c3389935bffc3..5e96d7a430be8a2ce6327b72aa1b09e17f9b306f 100644 (file)
@@ -11,7 +11,7 @@ struct IR_i2c {
        struct i2c_client      *c;
        struct input_dev       *input;
        struct ir_input_state  ir;
-
+       u64                    ir_type;
        /* Used to avoid fast repeating */
        unsigned char          old;
 
diff --git a/include/media/lirc.h b/include/media/lirc.h
new file mode 100644 (file)
index 0000000..42c467c
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * lirc.h - linux infrared remote control header file
+ * last modified 2010/07/13 by Jarod Wilson
+ */
+
+#ifndef _LINUX_LIRC_H
+#define _LINUX_LIRC_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define PULSE_BIT       0x01000000
+#define PULSE_MASK      0x00FFFFFF
+
+#define LIRC_MODE2_SPACE     0x00000000
+#define LIRC_MODE2_PULSE     0x01000000
+#define LIRC_MODE2_FREQUENCY 0x02000000
+#define LIRC_MODE2_TIMEOUT   0x03000000
+
+#define LIRC_VALUE_MASK      0x00FFFFFF
+#define LIRC_MODE2_MASK      0xFF000000
+
+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
+
+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
+
+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
+
+/* used heavily by lirc userspace */
+#define lirc_t int
+
+/*** lirc compatible hardware features ***/
+
+#define LIRC_MODE2SEND(x) (x)
+#define LIRC_SEND2MODE(x) (x)
+#define LIRC_MODE2REC(x) ((x) << 16)
+#define LIRC_REC2MODE(x) ((x) >> 16)
+
+#define LIRC_MODE_RAW                  0x00000001
+#define LIRC_MODE_PULSE                0x00000002
+#define LIRC_MODE_MODE2                0x00000004
+#define LIRC_MODE_LIRCCODE             0x00000010
+
+
+#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
+#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
+#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
+#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_SEND_MASK             0x0000003f
+
+#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
+#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
+#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
+
+#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
+#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
+#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
+#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
+
+#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
+#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
+
+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
+#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
+#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
+#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
+#define LIRC_CAN_SET_REC_FILTER           0x08000000
+
+#define LIRC_CAN_MEASURE_CARRIER          0x02000000
+
+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
+
+#define LIRC_CAN_NOTIFY_DECODE            0x01000000
+
+/*** IOCTL commands for lirc driver ***/
+
+#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
+
+#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
+#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
+#define LIRC_GET_SEND_CARRIER          _IOR('i', 0x00000003, __u32)
+#define LIRC_GET_REC_CARRIER           _IOR('i', 0x00000004, __u32)
+#define LIRC_GET_SEND_DUTY_CYCLE       _IOR('i', 0x00000005, __u32)
+#define LIRC_GET_REC_DUTY_CYCLE        _IOR('i', 0x00000006, __u32)
+#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
+
+#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
+#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
+
+#define LIRC_GET_MIN_FILTER_PULSE      _IOR('i', 0x0000000a, __u32)
+#define LIRC_GET_MAX_FILTER_PULSE      _IOR('i', 0x0000000b, __u32)
+#define LIRC_GET_MIN_FILTER_SPACE      _IOR('i', 0x0000000c, __u32)
+#define LIRC_GET_MAX_FILTER_SPACE      _IOR('i', 0x0000000d, __u32)
+
+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
+#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
+
+#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
+#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
+/* Note: these can reset the according pulse_width */
+#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
+#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
+#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
+#define LIRC_SET_REC_DUTY_CYCLE        _IOW('i', 0x00000016, __u32)
+#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
+
+/*
+ * when a timeout != 0 is set the driver will send a
+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
+ * never sent, timeout is disabled by default
+ */
+#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
+
+/* 1 enables, 0 disables timeout reports in MODE2 */
+#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
+
+/*
+ * pulses shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_PULSE      _IOW('i', 0x0000001a, __u32)
+/*
+ * spaces shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_SPACE      _IOW('i', 0x0000001b, __u32)
+/*
+ * if filter cannot be set independantly for pulse/space, this should
+ * be used
+ */
+#define LIRC_SET_REC_FILTER            _IOW('i', 0x0000001c, __u32)
+
+/*
+ * if enabled from the next key press on the driver will send
+ * LIRC_MODE2_FREQUENCY packets
+ */
+#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
+
+/*
+ * to set a range use
+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
+ * lower bound first and later
+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
+ */
+
+#define LIRC_SET_REC_DUTY_CYCLE_RANGE  _IOW('i', 0x0000001e, __u32)
+#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
+
+#define LIRC_NOTIFY_DECODE             _IO('i', 0x00000020)
+
+#define LIRC_SETUP_START               _IO('i', 0x00000021)
+#define LIRC_SETUP_END                 _IO('i', 0x00000022)
+
+#endif
diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h
new file mode 100644 (file)
index 0000000..b1f6066
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ *        This code is licensed under GNU GPL
+ *
+ */
+
+#ifndef _LINUX_LIRC_DEV_H
+#define _LINUX_LIRC_DEV_H
+
+#define MAX_IRCTL_DEVICES 4
+#define BUFLEN            16
+
+#define mod(n, div) ((n) % (div))
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/kfifo.h>
+#include <media/lirc.h>
+
+struct lirc_buffer {
+       wait_queue_head_t wait_poll;
+       spinlock_t fifo_lock;
+       unsigned int chunk_size;
+       unsigned int size; /* in chunks */
+       /* Using chunks instead of bytes pretends to simplify boundary checking
+        * And should allow for some performance fine tunning later */
+       struct kfifo fifo;
+       u8 fifo_initialized;
+};
+
+static inline void lirc_buffer_clear(struct lirc_buffer *buf)
+{
+       unsigned long flags;
+
+       if (buf->fifo_initialized) {
+               spin_lock_irqsave(&buf->fifo_lock, flags);
+               kfifo_reset(&buf->fifo);
+               spin_unlock_irqrestore(&buf->fifo_lock, flags);
+       } else
+               WARN(1, "calling %s on an uninitialized lirc_buffer\n",
+                    __func__);
+}
+
+static inline int lirc_buffer_init(struct lirc_buffer *buf,
+                                   unsigned int chunk_size,
+                                   unsigned int size)
+{
+       int ret;
+
+       init_waitqueue_head(&buf->wait_poll);
+       spin_lock_init(&buf->fifo_lock);
+       buf->chunk_size = chunk_size;
+       buf->size = size;
+       ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL);
+       if (ret == 0)
+               buf->fifo_initialized = 1;
+
+       return ret;
+}
+
+static inline void lirc_buffer_free(struct lirc_buffer *buf)
+{
+       if (buf->fifo_initialized) {
+               kfifo_free(&buf->fifo);
+               buf->fifo_initialized = 0;
+       } else
+               WARN(1, "calling %s on an uninitialized lirc_buffer\n",
+                    __func__);
+}
+
+static inline int lirc_buffer_len(struct lirc_buffer *buf)
+{
+       int len;
+       unsigned long flags;
+
+       spin_lock_irqsave(&buf->fifo_lock, flags);
+       len = kfifo_len(&buf->fifo);
+       spin_unlock_irqrestore(&buf->fifo_lock, flags);
+
+       return len;
+}
+
+static inline int lirc_buffer_full(struct lirc_buffer *buf)
+{
+       return lirc_buffer_len(buf) == buf->size * buf->chunk_size;
+}
+
+static inline int lirc_buffer_empty(struct lirc_buffer *buf)
+{
+       return !lirc_buffer_len(buf);
+}
+
+static inline int lirc_buffer_available(struct lirc_buffer *buf)
+{
+       return buf->size - (lirc_buffer_len(buf) / buf->chunk_size);
+}
+
+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf,
+                                           unsigned char *dest)
+{
+       unsigned int ret = 0;
+
+       if (lirc_buffer_len(buf) >= buf->chunk_size)
+               ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size,
+                                      &buf->fifo_lock);
+       return ret;
+
+}
+
+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,
+                                            unsigned char *orig)
+{
+       unsigned int ret;
+
+       ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size,
+                             &buf->fifo_lock);
+
+       return ret;
+}
+
+struct lirc_driver {
+       char name[40];
+       int minor;
+       unsigned long code_length;
+       unsigned int buffer_size; /* in chunks holding one code each */
+       int sample_rate;
+       unsigned long features;
+
+       unsigned int chunk_size;
+
+       void *data;
+       int min_timeout;
+       int max_timeout;
+       int (*add_to_buf) (void *data, struct lirc_buffer *buf);
+       struct lirc_buffer *rbuf;
+       int (*set_use_inc) (void *data);
+       void (*set_use_dec) (void *data);
+       struct file_operations *fops;
+       struct device *dev;
+       struct module *owner;
+};
+
+/* name:
+ * this string will be used for logs
+ *
+ * minor:
+ * indicates minor device (/dev/lirc) number for registered driver
+ * if caller fills it with negative value, then the first free minor
+ * number will be used (if available)
+ *
+ * code_length:
+ * length of the remote control key code expressed in bits
+ *
+ * sample_rate:
+ *
+ * data:
+ * it may point to any driver data and this pointer will be passed to
+ * all callback functions
+ *
+ * add_to_buf:
+ * add_to_buf will be called after specified period of the time or
+ * triggered by the external event, this behavior depends on value of
+ * the sample_rate this function will be called in user context. This
+ * routine should return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ *
+ * rbuf:
+ * if not NULL, it will be used as a read buffer, you will have to
+ * write to the buffer by other means, like irq's (see also
+ * lirc_serial.c).
+ *
+ * set_use_inc:
+ * set_use_inc will be called after device is opened
+ *
+ * set_use_dec:
+ * set_use_dec will be called after device is closed
+ *
+ * fops:
+ * file_operations for drivers which don't fit the current driver model.
+ *
+ * Some ioctl's can be directly handled by lirc_dev if the driver's
+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also
+ * lirc_serial.c).
+ *
+ * owner:
+ * the module owning this struct
+ *
+ */
+
+
+/* following functions can be called ONLY from user context
+ *
+ * returns negative value on error or minor number
+ * of the registered device if success
+ * contents of the structure pointed by p is copied
+ */
+extern int lirc_register_driver(struct lirc_driver *d);
+
+/* returns negative value on error or 0 if success
+*/
+extern int lirc_unregister_driver(int minor);
+
+/* Returns the private data stored in the lirc_driver
+ * associated with the given device file pointer.
+ */
+void *lirc_get_pdata(struct file *file);
+
+/* default file operations
+ * used by drivers if they override only some operations
+ */
+int lirc_dev_fop_open(struct inode *inode, struct file *file);
+int lirc_dev_fop_close(struct inode *inode, struct file *file);
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait);
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length,
+                         loff_t *ppos);
+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length,
+                          loff_t *ppos);
+
+#endif
index c78e99a435b6c019438059e84d72a67e55fc2bd8..9569d0863f8b98514d17b316b8ccce2d4d9379e5 100644 (file)
 #define IR_TYPE_RC6    (1  << 2)       /* Philips RC6 protocol */
 #define IR_TYPE_JVC    (1  << 3)       /* JVC protocol */
 #define IR_TYPE_SONY   (1  << 4)       /* Sony12/15/20 protocol */
+#define IR_TYPE_LIRC   (1  << 30)      /* Pass raw IR to lirc userspace */
 #define IR_TYPE_OTHER  (1u << 31)
 
+#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC  | IR_TYPE_RC6  | \
+                    IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \
+                    IR_TYPE_OTHER)
+
 struct ir_scancode {
        u32     scancode;
        u32     keycode;
@@ -64,6 +69,8 @@ void rc_map_init(void);
 #define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
 #define RC_MAP_CINERGY                   "rc-cinergy"
+#define RC_MAP_DIB0700_NEC_TABLE         "rc-dib0700-nec"
+#define RC_MAP_DIB0700_RC5_TABLE         "rc-dib0700-rc5"
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
@@ -87,6 +94,7 @@ void rc_map_init(void);
 #define RC_MAP_KAIOMY                    "rc-kaiomy"
 #define RC_MAP_KWORLD_315U               "rc-kworld-315u"
 #define RC_MAP_KWORLD_PLUS_TV_ANALOG     "rc-kworld-plus-tv-analog"
+#define RC_MAP_LIRC                      "rc-lirc"
 #define RC_MAP_MANLI                     "rc-manli"
 #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
 #define RC_MAP_MSI_TVANYWHERE            "rc-msi-tvanywhere"
@@ -107,6 +115,7 @@ void rc_map_init(void);
 #define RC_MAP_PV951                     "rc-pv951"
 #define RC_MAP_RC5_HAUPPAUGE_NEW         "rc-rc5-hauppauge-new"
 #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_TBS_NEC                   "rc-tbs-nec"
 #define RC_MAP_TERRATEC_CINERGY_XS       "rc-terratec-cinergy-xs"
@@ -116,6 +125,7 @@ void rc_map_init(void);
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
 #define RC_MAP_WINFAST                   "rc-winfast"
 #define RC_MAP_WINFAST_USBII_DELUXE      "rc-winfast-usbii-deluxe"
+
 /*
  * Please, do not just append newer Remote Controller names at the end.
  * The names should be ordered in alphabetical order
index b67747836878acd00544c38d3870bb35ed277c7c..80346a6d28a98c0ddd6354dabc09c1eb0765783e 100644 (file)
@@ -6,8 +6,11 @@
 #define SH_CEU_FLAG_HSYNC_LOW          (1 << 2) /* default High if possible */
 #define SH_CEU_FLAG_VSYNC_LOW          (1 << 3) /* default High if possible */
 
+struct device;
+
 struct sh_mobile_ceu_info {
        unsigned long flags;
+       struct device *csi2_dev;
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/sh_mobile_csi2.h b/include/media/sh_mobile_csi2.h
new file mode 100644 (file)
index 0000000..4d26151
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Driver header for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, 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 SH_MIPI_CSI
+#define SH_MIPI_CSI
+
+enum sh_csi2_phy {
+       SH_CSI2_PHY_MAIN,
+       SH_CSI2_PHY_SUB,
+};
+
+enum sh_csi2_type {
+       SH_CSI2C,
+       SH_CSI2I,
+};
+
+#define SH_CSI2_CRC    (1 << 0)
+#define SH_CSI2_ECC    (1 << 1)
+
+struct platform_device;
+
+struct sh_csi2_client_config {
+       enum sh_csi2_phy phy;
+       unsigned char lanes;            /* bitmask[3:0] */
+       unsigned char channel;          /* 0..3 */
+       struct platform_device *pdev;   /* client platform device */
+};
+
+struct sh_csi2_pdata {
+       enum sh_csi2_type type;
+       unsigned int flags;
+       struct sh_csi2_client_config *clients;
+       int num_clients;
+};
+
+struct device;
+struct v4l2_device;
+
+#endif
index b8289c2f609b431cf6da04388bdfd679a2db65c8..2ce957301f770b36af1c5b13ddd7c4b363354086 100644 (file)
 #ifndef SOC_CAMERA_H
 #define SOC_CAMERA_H
 
+#include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/videodev2.h>
 #include <media/videobuf-core.h>
 #include <media/v4l2-device.h>
 
+extern struct bus_type soc_camera_bus_type;
+
 struct soc_camera_device {
        struct list_head list;
        struct device dev;
index 865cda7cd611d729f634a231ee6ba54194dd0101..f0cf2e7def0664d2e55f6e9e9628132dca427366 100644 (file)
  */
 enum v4l2_mbus_pixelcode {
        V4L2_MBUS_FMT_FIXED = 1,
-       V4L2_MBUS_FMT_YUYV8_2X8_LE,
-       V4L2_MBUS_FMT_YVYU8_2X8_LE,
-       V4L2_MBUS_FMT_YUYV8_2X8_BE,
-       V4L2_MBUS_FMT_YVYU8_2X8_BE,
+       V4L2_MBUS_FMT_YUYV8_2X8,
+       V4L2_MBUS_FMT_YVYU8_2X8,
+       V4L2_MBUS_FMT_UYVY8_2X8,
+       V4L2_MBUS_FMT_VYUY8_2X8,
        V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
        V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
        V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -41,6 +41,11 @@ enum v4l2_mbus_pixelcode {
        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,
 };
 
 /**
index f91a736c133d95c29087a88d1763536f4526facd..f2c41cebf453a65abbe4fc281f20103287e5fea0 100644 (file)
@@ -54,8 +54,6 @@ struct videobuf_queue;
 
 struct videobuf_mapping {
        unsigned int count;
-       unsigned long start;
-       unsigned long end;
        struct videobuf_queue *q;
 };
 
@@ -127,7 +125,7 @@ struct videobuf_queue_ops {
 struct videobuf_qtype_ops {
        u32                     magic;
 
-       struct videobuf_buffer *(*alloc)(size_t size);
+       struct videobuf_buffer *(*alloc_vb)(size_t size);
        void *(*vaddr)          (struct videobuf_buffer *buf);
        int (*iolock)           (struct videobuf_queue *q,
                                 struct videobuf_buffer *vb,
@@ -173,7 +171,7 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
 int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
                struct v4l2_framebuffer *fbuf);
 
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q);
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q);
 
 /* Used on videobuf-dvb */
 void *videobuf_queue_to_vaddr(struct videobuf_queue *q,
index a195f3b9c00a7dba5bca7887ae2e64decb1c1411..97e07f46a0fae22f1cba1eb3073f5661cc97b95a 100644 (file)
 
 /* --------------------------------------------------------------------- */
 
-/*
- * Return a scatterlist for some page-aligned vmalloc()'ed memory
- * block (NULL on errors).  Memory for the scatterlist is allocated
- * using kmalloc.  The caller must free the memory.
- */
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
-
-/*
- * Return a scatterlist for a an array of userpages (NULL on errors).
- * Memory for the scatterlist is allocated using kmalloc.  The caller
- * must free the memory.
- */
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
-                                        int offset);
-
-/* --------------------------------------------------------------------- */
-
 /*
  * A small set of helper functions to manage buffers (both userland
  * and kernel) for DMA.
@@ -68,7 +51,7 @@ struct videobuf_dmabuf {
        struct page         **pages;
 
        /* for kernel buffers */
-       void                *vmalloc;
+       void                *vaddr;
 
        /* for overlay buffers (pci-pci dma) */
        dma_addr_t          bus_addr;
@@ -87,6 +70,16 @@ struct videobuf_dma_sg_memory {
        struct videobuf_dmabuf  dma;
 };
 
+/*
+ * Scatter-gather DMA buffer API.
+ *
+ * These functions provide a simple way to create a page list and a
+ * scatter-gather list from a kernel, userspace of physical address and map the
+ * memory for DMA operation.
+ *
+ * Despite the name, this is totally unrelated to videobuf, except that
+ * videobuf-dma-sg uses the same API internally.
+ */
 void videobuf_dma_init(struct videobuf_dmabuf *dma);
 int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
                           unsigned long data, unsigned long size);
@@ -96,8 +89,8 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
                              dma_addr_t addr, int nr_pages);
 int videobuf_dma_free(struct videobuf_dmabuf *dma);
 
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
 struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf);
 
 void *videobuf_sg_alloc(size_t size);
@@ -111,11 +104,5 @@ void videobuf_queue_sg_init(struct videobuf_queue *q,
                         unsigned int msize,
                         void *priv);
 
-/*FIXME: these variants are used only on *-alsa code, where videobuf is
- * used without queue
- */
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
-
 #endif /* _VIDEOBUF_DMA_SG_H */
 
index 851eb1a2ff2a802f5ebca553dc21e1134dc2992c..e19403c18dae59574b46a2dfd6952e78f2dcc56e 100644 (file)
@@ -22,7 +22,7 @@
 struct videobuf_vmalloc_memory {
        u32                 magic;
 
-       void                *vmalloc;
+       void                *vaddr;
 
        /* remap_vmalloc_range seems to need to run
         * after mmap() on some cases */
index 156c26bb8bd7d0f71057b0ec5d6f3802e4792054..a8de812ccbc8c68f15c0c434fdf5b70edcab707d 100644 (file)
@@ -88,8 +88,16 @@ do { \
  * enum p9_msg_t - 9P message types
  * @P9_TSTATFS: file system status request
  * @P9_RSTATFS: file system status response
+ * @P9_TSYMLINK: make symlink request
+ * @P9_RSYMLINK: make symlink response
+ * @P9_TMKNOD: create a special file object request
+ * @P9_RMKNOD: create a special file object response
+ * @P9_TLCREATE: prepare a handle for I/O on an new file for 9P2000.L
+ * @P9_RLCREATE: response with file access information for 9P2000.L
  * @P9_TRENAME: rename request
  * @P9_RRENAME: rename response
+ * @P9_TMKDIR: create a directory request
+ * @P9_RMKDIR: create a directory response
  * @P9_TVERSION: version handshake request
  * @P9_RVERSION: version handshake response
  * @P9_TAUTH: request to establish authentication channel
@@ -131,8 +139,30 @@ do { \
 enum p9_msg_t {
        P9_TSTATFS = 8,
        P9_RSTATFS,
+       P9_TLOPEN = 12,
+       P9_RLOPEN,
+       P9_TLCREATE = 14,
+       P9_RLCREATE,
+       P9_TSYMLINK = 16,
+       P9_RSYMLINK,
+       P9_TMKNOD = 18,
+       P9_RMKNOD,
        P9_TRENAME = 20,
        P9_RRENAME,
+       P9_TGETATTR = 24,
+       P9_RGETATTR,
+       P9_TSETATTR = 26,
+       P9_RSETATTR,
+       P9_TXATTRWALK = 30,
+       P9_RXATTRWALK,
+       P9_TXATTRCREATE = 32,
+       P9_RXATTRCREATE,
+       P9_TREADDIR = 40,
+       P9_RREADDIR,
+       P9_TLINK = 70,
+       P9_RLINK,
+       P9_TMKDIR = 72,
+       P9_RMKDIR,
        P9_TVERSION = 100,
        P9_RVERSION,
        P9_TAUTH = 102,
@@ -275,6 +305,9 @@ enum p9_qid_t {
 /* ample room for Twrite/Rread header */
 #define P9_IOHDRSZ     24
 
+/* Room for readdir header */
+#define P9_READDIRHDRSZ        24
+
 /**
  * struct p9_str - length prefixed string type
  * @len: length of the string
@@ -357,6 +390,74 @@ struct p9_wstat {
        u32 n_muid;             /* 9p2000.u extensions */
 };
 
+struct p9_stat_dotl {
+       u64 st_result_mask;
+       struct p9_qid qid;
+       u32 st_mode;
+       u32 st_uid;
+       u32 st_gid;
+       u64 st_nlink;
+       u64 st_rdev;
+       u64 st_size;
+       u64 st_blksize;
+       u64 st_blocks;
+       u64 st_atime_sec;
+       u64 st_atime_nsec;
+       u64 st_mtime_sec;
+       u64 st_mtime_nsec;
+       u64 st_ctime_sec;
+       u64 st_ctime_nsec;
+       u64 st_btime_sec;
+       u64 st_btime_nsec;
+       u64 st_gen;
+       u64 st_data_version;
+};
+
+#define P9_STATS_MODE          0x00000001ULL
+#define P9_STATS_NLINK         0x00000002ULL
+#define P9_STATS_UID           0x00000004ULL
+#define P9_STATS_GID           0x00000008ULL
+#define P9_STATS_RDEV          0x00000010ULL
+#define P9_STATS_ATIME         0x00000020ULL
+#define P9_STATS_MTIME         0x00000040ULL
+#define P9_STATS_CTIME         0x00000080ULL
+#define P9_STATS_INO           0x00000100ULL
+#define P9_STATS_SIZE          0x00000200ULL
+#define P9_STATS_BLOCKS                0x00000400ULL
+
+#define P9_STATS_BTIME         0x00000800ULL
+#define P9_STATS_GEN           0x00001000ULL
+#define P9_STATS_DATA_VERSION  0x00002000ULL
+
+#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
+#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
+
+/**
+ * struct p9_iattr_dotl - P9 inode attribute for setattr
+ * @valid: bitfield specifying which fields are valid
+ *         same as in struct iattr
+ * @mode: File permission bits
+ * @uid: user id of owner
+ * @gid: group id
+ * @size: File size
+ * @atime_sec: Last access time, seconds
+ * @atime_nsec: Last access time, nanoseconds
+ * @mtime_sec: Last modification time, seconds
+ * @mtime_nsec: Last modification time, nanoseconds
+ */
+
+struct p9_iattr_dotl {
+       u32 valid;
+       u32 mode;
+       u32 uid;
+       u32 gid;
+       u64 size;
+       u64 atime_sec;
+       u64 atime_nsec;
+       u64 mtime_sec;
+       u64 mtime_nsec;
+};
+
 /* Structures for Protocol Operations */
 struct p9_tstatfs {
        u32 fid;
@@ -485,6 +586,18 @@ struct p9_rwrite {
        u32 count;
 };
 
+struct p9_treaddir {
+       u32 fid;
+       u64 offset;
+       u32 count;
+};
+
+struct p9_rreaddir {
+       u32 count;
+       u8 *data;
+};
+
+
 struct p9_tclunk {
        u32 fid;
 };
index 7dd3ed85c782a928c42cecf878bb3e7bea8f4462..d1aa2cfb30f0f46b915e55118a29e7a8e91fe7e7 100644 (file)
@@ -195,6 +195,21 @@ struct p9_fid {
        struct list_head dlist; /* list of all fids attached to a dentry */
 };
 
+/**
+ * struct p9_dirent - directory entry structure
+ * @qid: The p9 server qid for this dirent
+ * @d_off: offset to the next dirent
+ * @d_type: type of file
+ * @d_name: file name
+ */
+
+struct p9_dirent {
+       struct p9_qid qid;
+       u64 d_off;
+       unsigned char d_type;
+       char d_name[256];
+};
+
 int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
 int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name);
 int p9_client_version(struct p9_client *);
@@ -211,15 +226,31 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
 int p9_client_open(struct p9_fid *fid, int mode);
 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
                                                        char *extension);
+int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname);
+int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
+                                                       struct p9_qid *qid);
+int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
+               gid_t gid, struct p9_qid *qid);
 int p9_client_clunk(struct p9_fid *fid);
 int p9_client_remove(struct p9_fid *fid);
 int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
                                                        u64 offset, u32 count);
 int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
                                                        u64 offset, u32 count);
+int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
+int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
+                                                       int proto_version);
 struct p9_wstat *p9_client_stat(struct p9_fid *fid);
 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
+int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *attr);
+
+struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
+                                                       u64 request_mask);
 
+int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode,
+                       dev_t rdev, gid_t gid, struct p9_qid *);
+int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
+                               gid_t gid, struct p9_qid *);
 struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
 void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
 
@@ -229,5 +260,7 @@ void p9stat_free(struct p9_wstat *);
 
 int p9_is_proto_dotu(struct p9_client *clnt);
 int p9_is_proto_dotl(struct p9_client *clnt);
+struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
+int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
 
 #endif /* NET_9P_CLIENT_H */
index a2d5504fbcc24abb44c44a158521617933df4367..60bc8b1e32e632eb2a51b318f1ae35486d01174f 100644 (file)
@@ -209,6 +209,31 @@ void exit_creds(struct task_struct *tsk)
        }
 }
 
+/**
+ * get_task_cred - Get another task's objective credentials
+ * @task: The task to query
+ *
+ * Get the objective credentials of a task, pinning them so that they can't go
+ * away.  Accessing a task's credentials directly is not permitted.
+ *
+ * The caller must also make sure task doesn't get deleted, either by holding a
+ * ref on task or by holding tasklist_lock to prevent it from being unlinked.
+ */
+const struct cred *get_task_cred(struct task_struct *task)
+{
+       const struct cred *cred;
+
+       rcu_read_lock();
+
+       do {
+               cred = __task_cred((task));
+               BUG_ON(!cred);
+       } while (!atomic_inc_not_zero(&((struct cred *)cred)->usage));
+
+       rcu_read_unlock();
+       return cred;
+}
+
 /*
  * Allocate blank credentials, such that the credentials can be filled in at a
  * later date without risk of ENOMEM.
index 250ed11d3ed2b83b8e2a87845fe97a7db096b33c..44524cc8c32a6ca179d67b8df91394c516ee6046 100644 (file)
@@ -114,7 +114,7 @@ static __init int test_atomic64(void)
        BUG_ON(v.counter != r);
 
 #if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
-    defined(CONFIG_S390) || defined(_ASM_GENERIC_ATOMIC64_H)
+    defined(CONFIG_S390) || defined(_ASM_GENERIC_ATOMIC64_H) || defined(CONFIG_ARM)
        INIT(onestwos);
        BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
        r -= one;
index a009055140ecf7a798625d3fee7cd856c0bb8d4c..34e3082632d8311575e27c6d2a4b87c9985dd574 100644 (file)
  */
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
 
-/*
- * Enumeration for sync targets
- */
-enum dma_sync_target {
-       SYNC_FOR_CPU = 0,
-       SYNC_FOR_DEVICE = 1,
-};
-
 int swiotlb_force;
 
 /*
- * Used to do a quick range check in unmap_single and
- * sync_single_*, to see if the memory was in fact allocated by this
+ * Used to do a quick range check in swiotlb_tbl_unmap_single and
+ * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
 static char *io_tlb_start, *io_tlb_end;
@@ -140,28 +132,14 @@ void swiotlb_print_info(void)
               (unsigned long long)pend);
 }
 
-/*
- * Statically reserve bounce buffer space and initialize bounce buffer data
- * structures for the software IO TLB used to implement the DMA API.
- */
-void __init
-swiotlb_init_with_default_size(size_t default_size, int verbose)
+void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
 {
        unsigned long i, bytes;
 
-       if (!io_tlb_nslabs) {
-               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
-               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
-       }
-
-       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+       bytes = nslabs << IO_TLB_SHIFT;
 
-       /*
-        * Get IO TLB memory from the low pages
-        */
-       io_tlb_start = alloc_bootmem_low_pages(bytes);
-       if (!io_tlb_start)
-               panic("Cannot allocate SWIOTLB buffer");
+       io_tlb_nslabs = nslabs;
+       io_tlb_start = tlb;
        io_tlb_end = io_tlb_start + bytes;
 
        /*
@@ -185,6 +163,32 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
                swiotlb_print_info();
 }
 
+/*
+ * Statically reserve bounce buffer space and initialize bounce buffer data
+ * structures for the software IO TLB used to implement the DMA API.
+ */
+void __init
+swiotlb_init_with_default_size(size_t default_size, int verbose)
+{
+       unsigned long bytes;
+
+       if (!io_tlb_nslabs) {
+               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
+               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+       }
+
+       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+       /*
+        * Get IO TLB memory from the low pages
+        */
+       io_tlb_start = alloc_bootmem_low_pages(bytes);
+       if (!io_tlb_start)
+               panic("Cannot allocate SWIOTLB buffer");
+
+       swiotlb_init_with_tbl(io_tlb_start, io_tlb_nslabs, verbose);
+}
+
 void __init
 swiotlb_init(int verbose)
 {
@@ -323,8 +327,8 @@ static int is_swiotlb_buffer(phys_addr_t paddr)
 /*
  * Bounce: copy the swiotlb buffer back to the original dma location
  */
-static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
-                          enum dma_data_direction dir)
+void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+                   enum dma_data_direction dir)
 {
        unsigned long pfn = PFN_DOWN(phys);
 
@@ -360,26 +364,25 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
                        memcpy(phys_to_virt(phys), dma_addr, size);
        }
 }
+EXPORT_SYMBOL_GPL(swiotlb_bounce);
 
-/*
- * Allocates bounce buffer and returns its kernel virtual address.
- */
-static void *
-map_single(struct device *hwdev, phys_addr_t phys, size_t size, int dir)
+void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+                            phys_addr_t phys, size_t size,
+                            enum dma_data_direction dir)
 {
        unsigned long flags;
        char *dma_addr;
        unsigned int nslots, stride, index, wrap;
        int i;
-       unsigned long start_dma_addr;
        unsigned long mask;
        unsigned long offset_slots;
        unsigned long max_slots;
 
        mask = dma_get_seg_boundary(hwdev);
-       start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start) & mask;
 
-       offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       tbl_dma_addr &= mask;
+
+       offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 
        /*
         * Carefully handle integer overflow which can occur when mask == ~0UL.
@@ -466,12 +469,27 @@ found:
 
        return dma_addr;
 }
+EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single);
+
+/*
+ * Allocates bounce buffer and returns its kernel virtual address.
+ */
+
+static void *
+map_single(struct device *hwdev, phys_addr_t phys, size_t size,
+          enum dma_data_direction dir)
+{
+       dma_addr_t start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start);
+
+       return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir);
+}
 
 /*
  * dma_addr is the kernel virtual address of the bounce buffer to unmap.
  */
-static void
-do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
+void
+swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size,
+                       enum dma_data_direction dir)
 {
        unsigned long flags;
        int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
@@ -509,10 +527,12 @@ do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
        }
        spin_unlock_irqrestore(&io_tlb_lock, flags);
 }
+EXPORT_SYMBOL_GPL(swiotlb_tbl_unmap_single);
 
-static void
-sync_single(struct device *hwdev, char *dma_addr, size_t size,
-           int dir, int target)
+void
+swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr, size_t size,
+                       enum dma_data_direction dir,
+                       enum dma_sync_target target)
 {
        int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
        phys_addr_t phys = io_tlb_orig_addr[index];
@@ -536,6 +556,7 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
                BUG();
        }
 }
+EXPORT_SYMBOL_GPL(swiotlb_tbl_sync_single);
 
 void *
 swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -559,8 +580,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
        }
        if (!ret) {
                /*
-                * We are either out of memory or the device can't DMA
-                * to GFP_DMA memory; fall back on map_single(), which
+                * We are either out of memory or the device can't DMA to
+                * GFP_DMA memory; fall back on map_single(), which
                 * will grab memory from the lowest available address range.
                 */
                ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE);
@@ -578,7 +599,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                       (unsigned long long)dev_addr);
 
                /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-               do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
+               swiotlb_tbl_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
                return NULL;
        }
        *dma_handle = dev_addr;
@@ -596,13 +617,14 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
        if (!is_swiotlb_buffer(paddr))
                free_pages((unsigned long)vaddr, get_order(size));
        else
-               /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-               do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
+               /* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */
+               swiotlb_tbl_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
 }
 EXPORT_SYMBOL(swiotlb_free_coherent);
 
 static void
-swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
+swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
+            int do_panic)
 {
        /*
         * Ran out of IOMMU space for this operation. This is very bad.
@@ -680,14 +702,14 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page);
  * whatever the device wrote there.
  */
 static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
-                        size_t size, int dir)
+                        size_t size, enum dma_data_direction dir)
 {
        phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
        BUG_ON(dir == DMA_NONE);
 
        if (is_swiotlb_buffer(paddr)) {
-               do_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
+               swiotlb_tbl_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
                return;
        }
 
@@ -723,14 +745,16 @@ EXPORT_SYMBOL_GPL(swiotlb_unmap_page);
  */
 static void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
-                   size_t size, int dir, int target)
+                   size_t size, enum dma_data_direction dir,
+                   enum dma_sync_target target)
 {
        phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
        BUG_ON(dir == DMA_NONE);
 
        if (is_swiotlb_buffer(paddr)) {
-               sync_single(hwdev, phys_to_virt(paddr), size, dir, target);
+               swiotlb_tbl_sync_single(hwdev, phys_to_virt(paddr), size, dir,
+                                      target);
                return;
        }
 
@@ -809,7 +833,7 @@ EXPORT_SYMBOL(swiotlb_map_sg_attrs);
 
 int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
-              int dir)
+              enum dma_data_direction dir)
 {
        return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
 }
@@ -836,7 +860,7 @@ EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
 
 void
 swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                int dir)
+                enum dma_data_direction dir)
 {
        return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
 }
@@ -851,7 +875,8 @@ EXPORT_SYMBOL(swiotlb_unmap_sg);
  */
 static void
 swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
-               int nelems, int dir, int target)
+               int nelems, enum dma_data_direction dir,
+               enum dma_sync_target target)
 {
        struct scatterlist *sg;
        int i;
index 119b7ccdf39b8ee542d3f4d695bff3c9d5322987..bde42c6d3633f15cfe51b1eae8e3e56833e86955 100644 (file)
@@ -1394,10 +1394,20 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                return i ? : -EFAULT;
                        }
                        if (pages) {
-                               struct page *page = vm_normal_page(gate_vma, start, *pte);
+                               struct page *page;
+
+                               page = vm_normal_page(gate_vma, start, *pte);
+                               if (!page) {
+                                       if (!(gup_flags & FOLL_DUMP) &&
+                                            is_zero_pfn(pte_pfn(*pte)))
+                                               page = pte_page(*pte);
+                                       else {
+                                               pte_unmap(pte);
+                                               return i ? : -EFAULT;
+                                       }
+                               }
                                pages[i] = page;
-                               if (page)
-                                       get_page(page);
+                               get_page(page);
                        }
                        pte_unmap(pte);
                        if (vmas)
index 37c8da07a80b080c6d93f9a2bdd1226873354af8..dc6f2f26d0230b1462ea1ea583c6fda5dc5b49c5 100644 (file)
@@ -460,7 +460,8 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
                        return err;
                }
 
-               if (p9_is_proto_dotu(c))
+               if (p9_is_proto_dotu(c) ||
+                       p9_is_proto_dotl(c))
                        err = -ecode;
 
                if (!err || !IS_ERR_VALUE(err))
@@ -1015,14 +1016,18 @@ int p9_client_open(struct p9_fid *fid, int mode)
        struct p9_qid qid;
        int iounit;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
-       err = 0;
        clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
+               p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
+       err = 0;
 
        if (fid->mode != -1)
                return -EINVAL;
 
-       req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
+       if (p9_is_proto_dotl(clnt))
+               req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode);
+       else
+               req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
                goto error;
@@ -1034,10 +1039,9 @@ int p9_client_open(struct p9_fid *fid, int mode)
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n",
-                               qid.type,
-                               (unsigned long long)qid.path,
-                               qid.version, iounit);
+       P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
+               p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN",  qid.type,
+               (unsigned long long)qid.path, qid.version, iounit);
 
        fid->mode = mode;
        fid->iounit = iounit;
@@ -1049,6 +1053,50 @@ error:
 }
 EXPORT_SYMBOL(p9_client_open);
 
+int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
+               gid_t gid, struct p9_qid *qid)
+{
+       int err = 0;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+       int iounit;
+
+       P9_DPRINTK(P9_DEBUG_9P,
+                       ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
+                       ofid->fid, name, flags, mode, gid);
+       clnt = ofid->clnt;
+
+       if (ofid->mode != -1)
+               return -EINVAL;
+
+       req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags,
+                       mode, gid);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto free_and_error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
+                       qid->type,
+                       (unsigned long long)qid->path,
+                       qid->version, iounit);
+
+       ofid->mode = mode;
+       ofid->iounit = iounit;
+
+free_and_error:
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_create_dotl);
+
 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
                     char *extension)
 {
@@ -1094,6 +1142,59 @@ error:
 }
 EXPORT_SYMBOL(p9_client_fcreate);
 
+int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
+               struct p9_qid *qid)
+{
+       int err = 0;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s  symtgt %s\n",
+                       dfid->fid, name, symtgt);
+       clnt = dfid->clnt;
+
+       req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt,
+                       gid);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto free_and_error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
+                       qid->type, (unsigned long long)qid->path, qid->version);
+
+free_and_error:
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_symlink);
+
+int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
+{
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
+                       dfid->fid, oldfid->fid, newname);
+       clnt = dfid->clnt;
+       req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
+                       newname);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n");
+       p9_free_req(clnt, req);
+       return 0;
+}
+EXPORT_SYMBOL(p9_client_link);
+
 int p9_client_clunk(struct p9_fid *fid)
 {
        int err;
@@ -1139,9 +1240,8 @@ int p9_client_remove(struct p9_fid *fid)
        P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
 
        p9_free_req(clnt, req);
-       p9_fid_destroy(fid);
-
 error:
+       p9_fid_destroy(fid);
        return err;
 }
 EXPORT_SYMBOL(p9_client_remove);
@@ -1302,6 +1402,65 @@ error:
 }
 EXPORT_SYMBOL(p9_client_stat);
 
+struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
+                                                       u64 request_mask)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl),
+                                                               GFP_KERNEL);
+       struct p9_req_t *req;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
+                                                       fid->fid, request_mask);
+
+       if (!ret)
+               return ERR_PTR(-ENOMEM);
+
+       err = 0;
+       clnt = fid->clnt;
+
+       req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               p9_free_req(clnt, req);
+               goto error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P,
+               "<<< RGETATTR st_result_mask=%lld\n"
+               "<<< qid=%x.%llx.%x\n"
+               "<<< st_mode=%8.8x st_nlink=%llu\n"
+               "<<< st_uid=%d st_gid=%d\n"
+               "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
+               "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
+               "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
+               "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
+               "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
+               "<<< st_gen=%lld st_data_version=%lld",
+               ret->st_result_mask, ret->qid.type, ret->qid.path,
+               ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid,
+               ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize,
+               ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec,
+               ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec,
+               ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec,
+               ret->st_gen, ret->st_data_version);
+
+       p9_free_req(clnt, req);
+       return ret;
+
+error:
+       kfree(ret);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_getattr_dotl);
+
 static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
 {
        int ret;
@@ -1366,6 +1525,36 @@ error:
 }
 EXPORT_SYMBOL(p9_client_wstat);
 
+int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
+{
+       int err;
+       struct p9_req_t *req;
+       struct p9_client *clnt;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
+       P9_DPRINTK(P9_DEBUG_9P,
+               "    valid=%x mode=%x uid=%d gid=%d size=%lld\n"
+               "    atime_sec=%lld atime_nsec=%lld\n"
+               "    mtime_sec=%lld mtime_nsec=%lld\n",
+               p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid,
+               p9attr->size, p9attr->atime_sec, p9attr->atime_nsec,
+               p9attr->mtime_sec, p9attr->mtime_nsec);
+
+       req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr);
+
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_setattr);
+
 int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
 {
        int err;
@@ -1432,3 +1621,187 @@ error:
 }
 EXPORT_SYMBOL(p9_client_rename);
 
+/*
+ * An xattrwalk without @attr_name gives the fid for the lisxattr namespace
+ */
+struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
+                               const char *attr_name, u64 *attr_size)
+{
+       int err;
+       struct p9_req_t *req;
+       struct p9_client *clnt;
+       struct p9_fid *attr_fid;
+
+       err = 0;
+       clnt = file_fid->clnt;
+       attr_fid = p9_fid_create(clnt);
+       if (IS_ERR(attr_fid)) {
+               err = PTR_ERR(attr_fid);
+               attr_fid = NULL;
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P,
+               ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n",
+               file_fid->fid, attr_fid->fid, attr_name);
+
+       req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
+                       file_fid->fid, attr_fid->fid, attr_name);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+       err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               p9_free_req(clnt, req);
+               goto clunk_fid;
+       }
+       p9_free_req(clnt, req);
+       P9_DPRINTK(P9_DEBUG_9P, "<<<  RXATTRWALK fid %d size %llu\n",
+               attr_fid->fid, *attr_size);
+       return attr_fid;
+clunk_fid:
+       p9_client_clunk(attr_fid);
+       attr_fid = NULL;
+error:
+       if (attr_fid && (attr_fid != file_fid))
+               p9_fid_destroy(attr_fid);
+
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(p9_client_xattrwalk);
+
+int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
+                       u64 attr_size, int flags)
+{
+       int err;
+       struct p9_req_t *req;
+       struct p9_client *clnt;
+
+       P9_DPRINTK(P9_DEBUG_9P,
+               ">>> TXATTRCREATE fid %d name  %s size %lld flag %d\n",
+               fid->fid, name, (long long)attr_size, flags);
+       err = 0;
+       clnt = fid->clnt;
+       req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd",
+                       fid->fid, name, attr_size, flags);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
+
+int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
+{
+       int err, rsize, total;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+       char *dataptr;
+
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
+                               fid->fid, (long long unsigned) offset, count);
+
+       err = 0;
+       clnt = fid->clnt;
+       total = 0;
+
+       rsize = fid->iounit;
+       if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
+               rsize = clnt->msize - P9_READDIRHDRSZ;
+
+       if (count < rsize)
+               rsize = count;
+
+       req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto error;
+       }
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto free_and_error;
+       }
+
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
+
+       if (data)
+               memmove(data, dataptr, count);
+
+       p9_free_req(clnt, req);
+       return count;
+
+free_and_error:
+       p9_free_req(clnt, req);
+error:
+       return err;
+}
+EXPORT_SYMBOL(p9_client_readdir);
+
+int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
+                       dev_t rdev, gid_t gid, struct p9_qid *qid)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
+               "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
+       req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode,
+               MAJOR(rdev), MINOR(rdev), gid);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
+                               (unsigned long long)qid->path, qid->version);
+
+error:
+       p9_free_req(clnt, req);
+       return err;
+
+}
+EXPORT_SYMBOL(p9_client_mknod_dotl);
+
+int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
+                               gid_t gid, struct p9_qid *qid)
+{
+       int err;
+       struct p9_client *clnt;
+       struct p9_req_t *req;
+
+       err = 0;
+       clnt = fid->clnt;
+       P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
+                fid->fid, name, mode, gid);
+       req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode,
+               gid);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+       if (err) {
+               p9pdu_dump(1, req->rc);
+               goto error;
+       }
+       P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
+                               (unsigned long long)qid->path, qid->version);
+
+error:
+       p9_free_req(clnt, req);
+       return err;
+
+}
+EXPORT_SYMBOL(p9_client_mkdir_dotl);
index 149f82160130684701118255d2ec73f31667c72d..3acd3afb20c857f6f3d2451a6ce1d7ba5c14af76 100644 (file)
@@ -141,6 +141,7 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
        D - data blob (int32_t size followed by void *, results are not freed)
        T - array of strings (int16_t count, followed by strings)
        R - array of qids (int16_t count, followed by qids)
+       A - stat for 9p2000.L (p9_stat_dotl)
        ? - if optional = 1, continue parsing
 */
 
@@ -340,6 +341,33 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                }
                        }
                        break;
+               case 'A': {
+                               struct p9_stat_dotl *stbuf =
+                                   va_arg(ap, struct p9_stat_dotl *);
+
+                               memset(stbuf, 0, sizeof(struct p9_stat_dotl));
+                               errcode =
+                                   p9pdu_readf(pdu, proto_version,
+                                       "qQdddqqqqqqqqqqqqqqq",
+                                       &stbuf->st_result_mask,
+                                       &stbuf->qid,
+                                       &stbuf->st_mode,
+                                       &stbuf->st_uid, &stbuf->st_gid,
+                                       &stbuf->st_nlink,
+                                       &stbuf->st_rdev, &stbuf->st_size,
+                                       &stbuf->st_blksize, &stbuf->st_blocks,
+                                       &stbuf->st_atime_sec,
+                                       &stbuf->st_atime_nsec,
+                                       &stbuf->st_mtime_sec,
+                                       &stbuf->st_mtime_nsec,
+                                       &stbuf->st_ctime_sec,
+                                       &stbuf->st_ctime_nsec,
+                                       &stbuf->st_btime_sec,
+                                       &stbuf->st_btime_nsec,
+                                       &stbuf->st_gen,
+                                       &stbuf->st_data_version);
+                       }
+                       break;
                case '?':
                        if ((proto_version != p9_proto_2000u) &&
                                (proto_version != p9_proto_2000L))
@@ -488,6 +516,23 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                }
                        }
                        break;
+               case 'I':{
+                               struct p9_iattr_dotl *p9attr = va_arg(ap,
+                                                       struct p9_iattr_dotl *);
+
+                               errcode = p9pdu_writef(pdu, proto_version,
+                                                       "ddddqqqqq",
+                                                       p9attr->valid,
+                                                       p9attr->mode,
+                                                       p9attr->uid,
+                                                       p9attr->gid,
+                                                       p9attr->size,
+                                                       p9attr->atime_sec,
+                                                       p9attr->atime_nsec,
+                                                       p9attr->mtime_sec,
+                                                       p9attr->mtime_nsec);
+                       }
+                       break;
                case '?':
                        if ((proto_version != p9_proto_2000u) &&
                                (proto_version != p9_proto_2000L))
@@ -580,3 +625,30 @@ void p9pdu_reset(struct p9_fcall *pdu)
        pdu->offset = 0;
        pdu->size = 0;
 }
+
+int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
+                                               int proto_version)
+{
+       struct p9_fcall fake_pdu;
+       int ret;
+       char *nameptr;
+
+       fake_pdu.size = len;
+       fake_pdu.capacity = len;
+       fake_pdu.sdata = buf;
+       fake_pdu.offset = 0;
+
+       ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
+                       &dirent->d_off, &dirent->d_type, &nameptr);
+       if (ret) {
+               P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
+               p9pdu_dump(1, &fake_pdu);
+               goto out;
+       }
+
+       strcpy(dirent->d_name, nameptr);
+
+out:
+       return fake_pdu.offset;
+}
+EXPORT_SYMBOL(p9dirent_read);
index 98ce9bcb0e15da4443ce08cd654576c2b235b69f..c85109d809caa4767ef2576c1947fcd877e432b7 100644 (file)
@@ -948,7 +948,7 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
 
        csocket = NULL;
 
-       if (strlen(addr) > UNIX_PATH_MAX) {
+       if (strlen(addr) >= UNIX_PATH_MAX) {
                P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
                        addr);
                return -ENAMETOOLONG;
index 226b9556b25f829384c107196d0110bdf75ef876..bd72ae6234947e424885f3808dbec54bddad244c 100644 (file)
@@ -140,6 +140,7 @@ config LSM_MMAP_MIN_ADDR
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
+source security/apparmor/Kconfig
 
 source security/integrity/ima/Kconfig
 
@@ -148,6 +149,7 @@ choice
        default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
        default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
        default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
+       default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
        default DEFAULT_SECURITY_DAC
 
        help
@@ -163,6 +165,9 @@ choice
        config DEFAULT_SECURITY_TOMOYO
                bool "TOMOYO" if SECURITY_TOMOYO=y
 
+       config DEFAULT_SECURITY_APPARMOR
+               bool "AppArmor" if SECURITY_APPARMOR=y
+
        config DEFAULT_SECURITY_DAC
                bool "Unix Discretionary Access Controls"
 
@@ -173,6 +178,7 @@ config DEFAULT_SECURITY
        default "selinux" if DEFAULT_SECURITY_SELINUX
        default "smack" if DEFAULT_SECURITY_SMACK
        default "tomoyo" if DEFAULT_SECURITY_TOMOYO
+       default "apparmor" if DEFAULT_SECURITY_APPARMOR
        default "" if DEFAULT_SECURITY_DAC
 
 endmenu
index da20a193c8dd6623d834ef9bb1396fcaacfd9bd0..8bb0fe9e1ca94e68cac077196fad183975955d95 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_KEYS)                      += keys/
 subdir-$(CONFIG_SECURITY_SELINUX)      += selinux
 subdir-$(CONFIG_SECURITY_SMACK)                += smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
+subdir-$(CONFIG_SECURITY_APPARMOR)     += apparmor
 
 # always enable default capabilities
 obj-y                                  += commoncap.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SECURITY_SELINUX)                += selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
 obj-$(CONFIG_AUDIT)                    += lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)          += tomoyo/built-in.o
+obj-$(CONFIG_SECURITY_APPARMOR)                += apparmor/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
new file mode 100644 (file)
index 0000000..0a0a99f
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Generated include files
+#
+af_names.h
+capability_names.h
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
new file mode 100644 (file)
index 0000000..72555b9
--- /dev/null
@@ -0,0 +1,31 @@
+config SECURITY_APPARMOR
+       bool "AppArmor support"
+       depends on SECURITY
+       select AUDIT
+       select SECURITY_PATH
+       select SECURITYFS
+       select SECURITY_NETWORK
+       default n
+       help
+         This enables the AppArmor security module.
+         Required userspace tools (if they are not included in your
+         distribution) and further information may be found at
+         http://apparmor.wiki.kernel.org
+
+         If you are unsure how to answer this question, answer N.
+
+config SECURITY_APPARMOR_BOOTPARAM_VALUE
+       int "AppArmor boot parameter default value"
+       depends on SECURITY_APPARMOR
+       range 0 1
+       default 1
+       help
+         This option sets the default value for the kernel parameter
+         'apparmor', which allows AppArmor to be enabled or disabled
+          at boot.  If this option is set to 0 (zero), the AppArmor
+         kernel parameter will default to 0, disabling AppArmor at
+         boot.  If this option is set to 1 (one), the AppArmor
+         kernel parameter will default to 1, enabling AppArmor at
+         boot.
+
+         If you are unsure how to answer this question, answer 1.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
new file mode 100644 (file)
index 0000000..f204869
--- /dev/null
@@ -0,0 +1,24 @@
+# Makefile for AppArmor Linux Security Module
+#
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+
+apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
+              path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
+              resource.o sid.o file.o
+
+clean-files: capability_names.h af_names.h
+
+quiet_cmd_make-caps = GEN     $@
+cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2]  = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
+
+quiet_cmd_make-rlim = GEN     $@
+cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2]  = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
+
+$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/resource.o : $(obj)/rlim_names.h
+$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
+       $(call cmd,make-caps)
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
+       $(call cmd,make-af)
+$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
+       $(call cmd,make-rlim)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
new file mode 100644 (file)
index 0000000..7320331
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /sys/kernel/security/apparmor interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/apparmorfs.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+/**
+ * aa_simple_write_to_buffer - common routine for getting policy from user
+ * @op: operation doing the user buffer copy
+ * @userbuf: user buffer to copy data from  (NOT NULL)
+ * @alloc_size: size of user buffer
+ * @copy_size: size of data to copy from user buffer
+ * @pos: position write is at in the file (NOT NULL)
+ *
+ * Returns: kernel buffer containing copy of user buffer data or an
+ *          ERR_PTR on failure.
+ */
+static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
+                                      size_t alloc_size, size_t copy_size,
+                                      loff_t *pos)
+{
+       char *data;
+
+       if (*pos != 0)
+               /* only writes from pos 0, that is complete writes */
+               return ERR_PTR(-ESPIPE);
+
+       /*
+        * Don't allow profile load/replace/remove from profiles that don't
+        * have CAP_MAC_ADMIN
+        */
+       if (!aa_may_manage_policy(op))
+               return ERR_PTR(-EACCES);
+
+       /* freed by caller to simple_write_to_buffer */
+       data = kvmalloc(alloc_size);
+       if (data == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       if (copy_from_user(data, userbuf, copy_size)) {
+               kvfree(data);
+               return ERR_PTR(-EFAULT);
+       }
+
+       return data;
+}
+
+
+/* .load file hook fn to load policy */
+static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
+                           loff_t *pos)
+{
+       char *data;
+       ssize_t error;
+
+       data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
+
+       error = PTR_ERR(data);
+       if (!IS_ERR(data)) {
+               error = aa_replace_profiles(data, size, PROF_ADD);
+               kvfree(data);
+       }
+
+       return error;
+}
+
+static const struct file_operations aa_fs_profile_load = {
+       .write = profile_load
+};
+
+/* .replace file hook fn to load and/or replace policy */
+static ssize_t profile_replace(struct file *f, const char __user *buf,
+                              size_t size, loff_t *pos)
+{
+       char *data;
+       ssize_t error;
+
+       data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
+       error = PTR_ERR(data);
+       if (!IS_ERR(data)) {
+               error = aa_replace_profiles(data, size, PROF_REPLACE);
+               kvfree(data);
+       }
+
+       return error;
+}
+
+static const struct file_operations aa_fs_profile_replace = {
+       .write = profile_replace
+};
+
+/* .remove file hook fn to remove loaded policy */
+static ssize_t profile_remove(struct file *f, const char __user *buf,
+                             size_t size, loff_t *pos)
+{
+       char *data;
+       ssize_t error;
+
+       /*
+        * aa_remove_profile needs a null terminated string so 1 extra
+        * byte is allocated and the copied data is null terminated.
+        */
+       data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
+
+       error = PTR_ERR(data);
+       if (!IS_ERR(data)) {
+               data[size] = 0;
+               error = aa_remove_profiles(data, size);
+               kvfree(data);
+       }
+
+       return error;
+}
+
+static const struct file_operations aa_fs_profile_remove = {
+       .write = profile_remove
+};
+
+/** Base file system setup **/
+
+static struct dentry *aa_fs_dentry __initdata;
+
+static void __init aafs_remove(const char *name)
+{
+       struct dentry *dentry;
+
+       dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
+       if (!IS_ERR(dentry)) {
+               securityfs_remove(dentry);
+               dput(dentry);
+       }
+}
+
+/**
+ * aafs_create - create an entry in the apparmor filesystem
+ * @name: name of the entry (NOT NULL)
+ * @mask: file permission mask of the file
+ * @fops: file operations for the file (NOT NULL)
+ *
+ * Used aafs_remove to remove entries created with this fn.
+ */
+static int __init aafs_create(const char *name, int mask,
+                             const struct file_operations *fops)
+{
+       struct dentry *dentry;
+
+       dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
+                                       NULL, fops);
+
+       return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+}
+
+/**
+ * aa_destroy_aafs - cleanup and free aafs
+ *
+ * releases dentries allocated by aa_create_aafs
+ */
+void __init aa_destroy_aafs(void)
+{
+       if (aa_fs_dentry) {
+               aafs_remove(".remove");
+               aafs_remove(".replace");
+               aafs_remove(".load");
+
+               securityfs_remove(aa_fs_dentry);
+               aa_fs_dentry = NULL;
+       }
+}
+
+/**
+ * aa_create_aafs - create the apparmor security filesystem
+ *
+ * dentries created here are released by aa_destroy_aafs
+ *
+ * Returns: error on failure
+ */
+int __init aa_create_aafs(void)
+{
+       int error;
+
+       if (!apparmor_initialized)
+               return 0;
+
+       if (aa_fs_dentry) {
+               AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
+               return -EEXIST;
+       }
+
+       aa_fs_dentry = securityfs_create_dir("apparmor", NULL);
+       if (IS_ERR(aa_fs_dentry)) {
+               error = PTR_ERR(aa_fs_dentry);
+               aa_fs_dentry = NULL;
+               goto error;
+       }
+
+       error = aafs_create(".load", 0640, &aa_fs_profile_load);
+       if (error)
+               goto error;
+       error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
+       if (error)
+               goto error;
+       error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
+       if (error)
+               goto error;
+
+       /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
+
+       /* Report that AppArmor fs is enabled */
+       aa_info_message("AppArmor Filesystem Enabled");
+       return 0;
+
+error:
+       aa_destroy_aafs();
+       AA_ERROR("Error creating AppArmor securityfs\n");
+       return error;
+}
+
+fs_initcall(aa_create_aafs);
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
new file mode 100644 (file)
index 0000000..96502b2
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor auditing functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/audit.h>
+#include <linux/socket.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/policy.h"
+
+const char *op_table[] = {
+       "null",
+
+       "sysctl",
+       "capable",
+
+       "unlink",
+       "mkdir",
+       "rmdir",
+       "mknod",
+       "truncate",
+       "link",
+       "symlink",
+       "rename_src",
+       "rename_dest",
+       "chmod",
+       "chown",
+       "getattr",
+       "open",
+
+       "file_perm",
+       "file_lock",
+       "file_mmap",
+       "file_mprotect",
+
+       "create",
+       "post_create",
+       "bind",
+       "connect",
+       "listen",
+       "accept",
+       "sendmsg",
+       "recvmsg",
+       "getsockname",
+       "getpeername",
+       "getsockopt",
+       "setsockopt",
+       "socket_shutdown",
+
+       "ptrace",
+
+       "exec",
+       "change_hat",
+       "change_profile",
+       "change_onexec",
+
+       "setprocattr",
+       "setrlimit",
+
+       "profile_replace",
+       "profile_load",
+       "profile_remove"
+};
+
+const char *audit_mode_names[] = {
+       "normal",
+       "quiet_denied",
+       "quiet",
+       "noquiet",
+       "all"
+};
+
+static char *aa_audit_type[] = {
+       "AUDIT",
+       "ALLOWED",
+       "DENIED",
+       "HINT",
+       "STATUS",
+       "ERROR",
+       "KILLED"
+};
+
+/*
+ * Currently AppArmor auditing is fed straight into the audit framework.
+ *
+ * TODO:
+ * netlink interface for complain mode
+ * user auditing, - send user auditing to netlink interface
+ * system control of whether user audit messages go to system log
+ */
+
+/**
+ * audit_base - core AppArmor function.
+ * @ab: audit buffer to fill (NOT NULL)
+ * @ca: audit structure containing data to audit (NOT NULL)
+ *
+ * Record common AppArmor audit data from @sa
+ */
+static void audit_pre(struct audit_buffer *ab, void *ca)
+{
+       struct common_audit_data *sa = ca;
+       struct task_struct *tsk = sa->tsk ? sa->tsk : current;
+
+       if (aa_g_audit_header) {
+               audit_log_format(ab, "apparmor=");
+               audit_log_string(ab, aa_audit_type[sa->aad.type]);
+       }
+
+       if (sa->aad.op) {
+               audit_log_format(ab, " operation=");
+               audit_log_string(ab, op_table[sa->aad.op]);
+       }
+
+       if (sa->aad.info) {
+               audit_log_format(ab, " info=");
+               audit_log_string(ab, sa->aad.info);
+               if (sa->aad.error)
+                       audit_log_format(ab, " error=%d", sa->aad.error);
+       }
+
+       if (sa->aad.profile) {
+               struct aa_profile *profile = sa->aad.profile;
+               pid_t pid;
+               rcu_read_lock();
+               pid = tsk->real_parent->pid;
+               rcu_read_unlock();
+               audit_log_format(ab, " parent=%d", pid);
+               if (profile->ns != root_ns) {
+                       audit_log_format(ab, " namespace=");
+                       audit_log_untrustedstring(ab, profile->ns->base.hname);
+               }
+               audit_log_format(ab, " profile=");
+               audit_log_untrustedstring(ab, profile->base.hname);
+       }
+
+       if (sa->aad.name) {
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, sa->aad.name);
+       }
+}
+
+/**
+ * aa_audit_msg - Log a message to the audit subsystem
+ * @sa: audit event structure (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ */
+void aa_audit_msg(int type, struct common_audit_data *sa,
+                 void (*cb) (struct audit_buffer *, void *))
+{
+       sa->aad.type = type;
+       sa->lsm_pre_audit = audit_pre;
+       sa->lsm_post_audit = cb;
+       common_lsm_audit(sa);
+}
+
+/**
+ * aa_audit - Log a profile based audit event to the audit subsystem
+ * @type: audit type for the message
+ * @profile: profile to check against (NOT NULL)
+ * @gfp: allocation flags to use
+ * @sa: audit event (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ *
+ * Handle default message switching based off of audit mode flags
+ *
+ * Returns: error on failure
+ */
+int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
+            struct common_audit_data *sa,
+            void (*cb) (struct audit_buffer *, void *))
+{
+       BUG_ON(!profile);
+
+       if (type == AUDIT_APPARMOR_AUTO) {
+               if (likely(!sa->aad.error)) {
+                       if (AUDIT_MODE(profile) != AUDIT_ALL)
+                               return 0;
+                       type = AUDIT_APPARMOR_AUDIT;
+               } else if (COMPLAIN_MODE(profile))
+                       type = AUDIT_APPARMOR_ALLOWED;
+               else
+                       type = AUDIT_APPARMOR_DENIED;
+       }
+       if (AUDIT_MODE(profile) == AUDIT_QUIET ||
+           (type == AUDIT_APPARMOR_DENIED &&
+            AUDIT_MODE(profile) == AUDIT_QUIET))
+               return sa->aad.error;
+
+       if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
+               type = AUDIT_APPARMOR_KILL;
+
+       if (!unconfined(profile))
+               sa->aad.profile = profile;
+
+       aa_audit_msg(type, sa, cb);
+
+       if (sa->aad.type == AUDIT_APPARMOR_KILL)
+               (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
+
+       if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
+               return complain_error(sa->aad.error);
+
+       return sa->aad.error;
+}
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
new file mode 100644 (file)
index 0000000..9982c48
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor capability mediation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+
+#include "include/apparmor.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/policy.h"
+#include "include/audit.h"
+
+/*
+ * Table of capability names: we generate it from capabilities.h.
+ */
+#include "capability_names.h"
+
+struct audit_cache {
+       struct aa_profile *profile;
+       kernel_cap_t caps;
+};
+
+static DEFINE_PER_CPU(struct audit_cache, audit_cache);
+
+/**
+ * audit_cb - call back for capability components of audit struct
+ * @ab - audit buffer   (NOT NULL)
+ * @va - audit struct to audit data from  (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+       audit_log_format(ab, " capname=");
+       audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
+}
+
+/**
+ * audit_caps - audit a capability
+ * @profile: profile confining task (NOT NULL)
+ * @task: task capability test was performed against (NOT NULL)
+ * @cap: capability tested
+ * @error: error code returned by test
+ *
+ * Do auditing of capability and handle, audit/complain/kill modes switching
+ * and duplicate message elimination.
+ *
+ * Returns: 0 or sa->error on success,  error code on failure
+ */
+static int audit_caps(struct aa_profile *profile, struct task_struct *task,
+                     int cap, int error)
+{
+       struct audit_cache *ent;
+       int type = AUDIT_APPARMOR_AUTO;
+       struct common_audit_data sa;
+       COMMON_AUDIT_DATA_INIT(&sa, CAP);
+       sa.tsk = task;
+       sa.u.cap = cap;
+       sa.aad.op = OP_CAPABLE;
+       sa.aad.error = error;
+
+       if (likely(!error)) {
+               /* test if auditing is being forced */
+               if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+                          !cap_raised(profile->caps.audit, cap)))
+                       return 0;
+               type = AUDIT_APPARMOR_AUDIT;
+       } else if (KILL_MODE(profile) ||
+                  cap_raised(profile->caps.kill, cap)) {
+               type = AUDIT_APPARMOR_KILL;
+       } else if (cap_raised(profile->caps.quiet, cap) &&
+                  AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+                  AUDIT_MODE(profile) != AUDIT_ALL) {
+               /* quiet auditing */
+               return error;
+       }
+
+       /* Do simple duplicate message elimination */
+       ent = &get_cpu_var(audit_cache);
+       if (profile == ent->profile && cap_raised(ent->caps, cap)) {
+               put_cpu_var(audit_cache);
+               if (COMPLAIN_MODE(profile))
+                       return complain_error(error);
+               return error;
+       } else {
+               aa_put_profile(ent->profile);
+               ent->profile = aa_get_profile(profile);
+               cap_raise(ent->caps, cap);
+       }
+       put_cpu_var(audit_cache);
+
+       return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
+}
+
+/**
+ * profile_capable - test if profile allows use of capability @cap
+ * @profile: profile being enforced    (NOT NULL, NOT unconfined)
+ * @cap: capability to test if allowed
+ *
+ * Returns: 0 if allowed else -EPERM
+ */
+static int profile_capable(struct aa_profile *profile, int cap)
+{
+       return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
+}
+
+/**
+ * aa_capable - test permission to use capability
+ * @task: task doing capability test against (NOT NULL)
+ * @profile: profile confining @task (NOT NULL)
+ * @cap: capability to be tested
+ * @audit: whether an audit record should be generated
+ *
+ * Look up capability in profile capability set.
+ *
+ * Returns: 0 on success, or else an error code.
+ */
+int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
+              int audit)
+{
+       int error = profile_capable(profile, cap);
+
+       if (!audit) {
+               if (COMPLAIN_MODE(profile))
+                       return complain_error(error);
+               return error;
+       }
+
+       return audit_caps(profile, task, cap, error);
+}
diff --git a/security/apparmor/context.c b/security/apparmor/context.c
new file mode 100644 (file)
index 0000000..8a9b502
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor functions used to manipulate object security
+ * contexts.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ *
+ *
+ * AppArmor sets confinement on every task, via the the aa_task_cxt and
+ * the aa_task_cxt.profile, both of which are required and are not allowed
+ * to be NULL.  The aa_task_cxt is not reference counted and is unique
+ * to each cred (which is reference count).  The profile pointed to by
+ * the task_cxt is reference counted.
+ *
+ * TODO
+ * If a task uses change_hat it currently does not return to the old
+ * cred or task context but instead creates a new one.  Ideally the task
+ * should return to the previous cred if it has not been modified.
+ *
+ */
+
+#include "include/context.h"
+#include "include/policy.h"
+
+/**
+ * aa_alloc_task_context - allocate a new task_cxt
+ * @flags: gfp flags for allocation
+ *
+ * Returns: allocated buffer or NULL on failure
+ */
+struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
+{
+       return kzalloc(sizeof(struct aa_task_cxt), flags);
+}
+
+/**
+ * aa_free_task_context - free a task_cxt
+ * @cxt: task_cxt to free (MAYBE NULL)
+ */
+void aa_free_task_context(struct aa_task_cxt *cxt)
+{
+       if (cxt) {
+               aa_put_profile(cxt->profile);
+               aa_put_profile(cxt->previous);
+               aa_put_profile(cxt->onexec);
+
+               kzfree(cxt);
+       }
+}
+
+/**
+ * aa_dup_task_context - duplicate a task context, incrementing reference counts
+ * @new: a blank task context      (NOT NULL)
+ * @old: the task context to copy  (NOT NULL)
+ */
+void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
+{
+       *new = *old;
+       aa_get_profile(new->profile);
+       aa_get_profile(new->previous);
+       aa_get_profile(new->onexec);
+}
+
+/**
+ * aa_replace_current_profile - replace the current tasks profiles
+ * @profile: new profile  (NOT NULL)
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_replace_current_profile(struct aa_profile *profile)
+{
+       struct aa_task_cxt *cxt = current_cred()->security;
+       struct cred *new;
+       BUG_ON(!profile);
+
+       if (cxt->profile == profile)
+               return 0;
+
+       new  = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       cxt = new->security;
+       if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
+               /* if switching to unconfined or a different profile namespace
+                * clear out context state
+                */
+               aa_put_profile(cxt->previous);
+               aa_put_profile(cxt->onexec);
+               cxt->previous = NULL;
+               cxt->onexec = NULL;
+               cxt->token = 0;
+       }
+       /* be careful switching cxt->profile, when racing replacement it
+        * is possible that cxt->profile->replacedby is the reference keeping
+        * @profile valid, so make sure to get its reference before dropping
+        * the reference on cxt->profile */
+       aa_get_profile(profile);
+       aa_put_profile(cxt->profile);
+       cxt->profile = profile;
+
+       commit_creds(new);
+       return 0;
+}
+
+/**
+ * aa_set_current_onexec - set the tasks change_profile to happen onexec
+ * @profile: system profile to set at exec  (MAYBE NULL to clear value)
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_set_current_onexec(struct aa_profile *profile)
+{
+       struct aa_task_cxt *cxt;
+       struct cred *new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       cxt = new->security;
+       aa_get_profile(profile);
+       aa_put_profile(cxt->onexec);
+       cxt->onexec = profile;
+
+       commit_creds(new);
+       return 0;
+}
+
+/**
+ * aa_set_current_hat - set the current tasks hat
+ * @profile: profile to set as the current hat  (NOT NULL)
+ * @token: token value that must be specified to change from the hat
+ *
+ * Do switch of tasks hat.  If the task is currently in a hat
+ * validate the token to match.
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_set_current_hat(struct aa_profile *profile, u64 token)
+{
+       struct aa_task_cxt *cxt;
+       struct cred *new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       BUG_ON(!profile);
+
+       cxt = new->security;
+       if (!cxt->previous) {
+               /* transfer refcount */
+               cxt->previous = cxt->profile;
+               cxt->token = token;
+       } else if (cxt->token == token) {
+               aa_put_profile(cxt->profile);
+       } else {
+               /* previous_profile && cxt->token != token */
+               abort_creds(new);
+               return -EACCES;
+       }
+       cxt->profile = aa_get_profile(aa_newest_version(profile));
+       /* clear exec on switching context */
+       aa_put_profile(cxt->onexec);
+       cxt->onexec = NULL;
+
+       commit_creds(new);
+       return 0;
+}
+
+/**
+ * aa_restore_previous_profile - exit from hat context restoring the profile
+ * @token: the token that must be matched to exit hat context
+ *
+ * Attempt to return out of a hat to the previous profile.  The token
+ * must match the stored token value.
+ *
+ * Returns: 0 or error of failure
+ */
+int aa_restore_previous_profile(u64 token)
+{
+       struct aa_task_cxt *cxt;
+       struct cred *new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       cxt = new->security;
+       if (cxt->token != token) {
+               abort_creds(new);
+               return -EACCES;
+       }
+       /* ignore restores when there is no saved profile */
+       if (!cxt->previous) {
+               abort_creds(new);
+               return 0;
+       }
+
+       aa_put_profile(cxt->profile);
+       cxt->profile = aa_newest_version(cxt->previous);
+       BUG_ON(!cxt->profile);
+       if (unlikely(cxt->profile != cxt->previous)) {
+               aa_get_profile(cxt->profile);
+               aa_put_profile(cxt->previous);
+       }
+       /* clear exec && prev information when restoring to previous context */
+       cxt->previous = NULL;
+       cxt->token = 0;
+       aa_put_profile(cxt->onexec);
+       cxt->onexec = NULL;
+
+       commit_creds(new);
+       return 0;
+}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
new file mode 100644 (file)
index 0000000..c825c6e
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy attachment and domain transitions
+ *
+ * Copyright (C) 2002-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/syscalls.h>
+#include <linux/tracehook.h>
+#include <linux/personality.h>
+
+#include "include/audit.h"
+#include "include/apparmorfs.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+/**
+ * aa_free_domain_entries - free entries in a domain table
+ * @domain: the domain table to free  (MAYBE NULL)
+ */
+void aa_free_domain_entries(struct aa_domain *domain)
+{
+       int i;
+       if (domain) {
+               if (!domain->table)
+                       return;
+
+               for (i = 0; i < domain->size; i++)
+                       kzfree(domain->table[i]);
+               kzfree(domain->table);
+               domain->table = NULL;
+       }
+}
+
+/**
+ * may_change_ptraced_domain - check if can change profile on ptraced task
+ * @task: task we want to change profile of   (NOT NULL)
+ * @to_profile: profile to change to  (NOT NULL)
+ *
+ * Check if the task is ptraced and if so if the tracing task is allowed
+ * to trace the new domain
+ *
+ * Returns: %0 or error if change not allowed
+ */
+static int may_change_ptraced_domain(struct task_struct *task,
+                                    struct aa_profile *to_profile)
+{
+       struct task_struct *tracer;
+       const struct cred *cred = NULL;
+       struct aa_profile *tracerp = NULL;
+       int error = 0;
+
+       rcu_read_lock();
+       tracer = tracehook_tracer_task(task);
+       if (tracer) {
+               /* released below */
+               cred = get_task_cred(tracer);
+               tracerp = aa_cred_profile(cred);
+       }
+       rcu_read_unlock();
+
+       /* not ptraced */
+       if (!tracer || unconfined(tracerp))
+               goto out;
+
+       error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
+
+out:
+       if (cred)
+               put_cred(cred);
+
+       return error;
+}
+
+/**
+ * change_profile_perms - find permissions for change_profile
+ * @profile: the current profile  (NOT NULL)
+ * @ns: the namespace being switched to  (NOT NULL)
+ * @name: the name of the profile to change to  (NOT NULL)
+ * @request: requested perms
+ * @start: state to start matching in
+ *
+ * Returns: permission set
+ */
+static struct file_perms change_profile_perms(struct aa_profile *profile,
+                                             struct aa_namespace *ns,
+                                             const char *name, u32 request,
+                                             unsigned int start)
+{
+       struct file_perms perms;
+       struct path_cond cond = { };
+       unsigned int state;
+
+       if (unconfined(profile)) {
+               perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
+               perms.audit = perms.quiet = perms.kill = 0;
+               return perms;
+       } else if (!profile->file.dfa) {
+               return nullperms;
+       } else if ((ns == profile->ns)) {
+               /* try matching against rules with out namespace prepended */
+               aa_str_perms(profile->file.dfa, start, name, &cond, &perms);
+               if (COMBINED_PERM_MASK(perms) & request)
+                       return perms;
+       }
+
+       /* try matching with namespace name and then profile */
+       state = aa_dfa_match(profile->file.dfa, start, ns->base.name);
+       state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
+       aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
+
+       return perms;
+}
+
+/**
+ * __attach_match_ - find an attachment match
+ * @name - to match against  (NOT NULL)
+ * @head - profile list to walk  (NOT NULL)
+ *
+ * Do a linear search on the profiles in the list.  There is a matching
+ * preference where an exact match is preferred over a name which uses
+ * expressions to match, and matching expressions with the greatest
+ * xmatch_len are preferred.
+ *
+ * Requires: @head not be shared or have appropriate locks held
+ *
+ * Returns: profile or NULL if no match found
+ */
+static struct aa_profile *__attach_match(const char *name,
+                                        struct list_head *head)
+{
+       int len = 0;
+       struct aa_profile *profile, *candidate = NULL;
+
+       list_for_each_entry(profile, head, base.list) {
+               if (profile->flags & PFLAG_NULL)
+                       continue;
+               if (profile->xmatch && profile->xmatch_len > len) {
+                       unsigned int state = aa_dfa_match(profile->xmatch,
+                                                         DFA_START, name);
+                       u32 perm = dfa_user_allow(profile->xmatch, state);
+                       /* any accepting state means a valid match. */
+                       if (perm & MAY_EXEC) {
+                               candidate = profile;
+                               len = profile->xmatch_len;
+                       }
+               } else if (!strcmp(profile->base.name, name))
+                       /* exact non-re match, no more searching required */
+                       return profile;
+       }
+
+       return candidate;
+}
+
+/**
+ * find_attach - do attachment search for unconfined processes
+ * @ns: the current namespace  (NOT NULL)
+ * @list: list to search  (NOT NULL)
+ * @name: the executable name to match against  (NOT NULL)
+ *
+ * Returns: profile or NULL if no match found
+ */
+static struct aa_profile *find_attach(struct aa_namespace *ns,
+                                     struct list_head *list, const char *name)
+{
+       struct aa_profile *profile;
+
+       read_lock(&ns->lock);
+       profile = aa_get_profile(__attach_match(name, list));
+       read_unlock(&ns->lock);
+
+       return profile;
+}
+
+/**
+ * separate_fqname - separate the namespace and profile names
+ * @fqname: the fqname name to split  (NOT NULL)
+ * @ns_name: the namespace name if it exists  (NOT NULL)
+ *
+ * This is the xtable equivalent routine of aa_split_fqname.  It finds the
+ * split in an xtable fqname which contains an embedded \0 instead of a :
+ * if a namespace is specified.  This is done so the xtable is constant and
+ * isn't re-split on every lookup.
+ *
+ * Either the profile or namespace name may be optional but if the namespace
+ * is specified the profile name termination must be present.  This results
+ * in the following possible encodings:
+ * profile_name\0
+ * :ns_name\0profile_name\0
+ * :ns_name\0\0
+ *
+ * NOTE: the xtable fqname is pre-validated at load time in unpack_trans_table
+ *
+ * Returns: profile name if it is specified else NULL
+ */
+static const char *separate_fqname(const char *fqname, const char **ns_name)
+{
+       const char *name;
+
+       if (fqname[0] == ':') {
+               /* In this case there is guaranteed to be two \0 terminators
+                * in the string.  They are verified at load time by
+                * by unpack_trans_table
+                */
+               *ns_name = fqname + 1;          /* skip : */
+               name = *ns_name + strlen(*ns_name) + 1;
+               if (!*name)
+                       name = NULL;
+       } else {
+               *ns_name = NULL;
+               name = fqname;
+       }
+
+       return name;
+}
+
+static const char *next_name(int xtype, const char *name)
+{
+       return NULL;
+}
+
+/**
+ * x_table_lookup - lookup an x transition name via transition table
+ * @profile: current profile (NOT NULL)
+ * @xindex: index into x transition table
+ *
+ * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
+ */
+static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+{
+       struct aa_profile *new_profile = NULL;
+       struct aa_namespace *ns = profile->ns;
+       u32 xtype = xindex & AA_X_TYPE_MASK;
+       int index = xindex & AA_X_INDEX_MASK;
+       const char *name;
+
+       /* index is guaranteed to be in range, validated at load time */
+       for (name = profile->file.trans.table[index]; !new_profile && name;
+            name = next_name(xtype, name)) {
+               struct aa_namespace *new_ns;
+               const char *xname = NULL;
+
+               new_ns = NULL;
+               if (xindex & AA_X_CHILD) {
+                       /* release by caller */
+                       new_profile = aa_find_child(profile, name);
+                       continue;
+               } else if (*name == ':') {
+                       /* switching namespace */
+                       const char *ns_name;
+                       xname = name = separate_fqname(name, &ns_name);
+                       if (!xname)
+                               /* no name so use profile name */
+                               xname = profile->base.hname;
+                       if (*ns_name == '@') {
+                               /* TODO: variable support */
+                               ;
+                       }
+                       /* released below */
+                       new_ns = aa_find_namespace(ns, ns_name);
+                       if (!new_ns)
+                               continue;
+               } else if (*name == '@') {
+                       /* TODO: variable support */
+                       continue;
+               } else {
+                       /* basic namespace lookup */
+                       xname = name;
+               }
+
+               /* released by caller */
+               new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname);
+               aa_put_namespace(new_ns);
+       }
+
+       /* released by caller */
+       return new_profile;
+}
+
+/**
+ * x_to_profile - get target profile for a given xindex
+ * @profile: current profile  (NOT NULL)
+ * @name: name to lookup (NOT NULL)
+ * @xindex: index into x transition table
+ *
+ * find profile for a transition index
+ *
+ * Returns: refcounted profile or NULL if not found available
+ */
+static struct aa_profile *x_to_profile(struct aa_profile *profile,
+                                      const char *name, u32 xindex)
+{
+       struct aa_profile *new_profile = NULL;
+       struct aa_namespace *ns = profile->ns;
+       u32 xtype = xindex & AA_X_TYPE_MASK;
+
+       switch (xtype) {
+       case AA_X_NONE:
+               /* fail exec unless ix || ux fallback - handled by caller */
+               return NULL;
+       case AA_X_NAME:
+               if (xindex & AA_X_CHILD)
+                       /* released by caller */
+                       new_profile = find_attach(ns, &profile->base.profiles,
+                                                 name);
+               else
+                       /* released by caller */
+                       new_profile = find_attach(ns, &ns->base.profiles,
+                                                 name);
+               break;
+       case AA_X_TABLE:
+               /* released by caller */
+               new_profile = x_table_lookup(profile, xindex);
+               break;
+       }
+
+       /* released by caller */
+       return new_profile;
+}
+
+/**
+ * apparmor_bprm_set_creds - set the new creds on the bprm struct
+ * @bprm: binprm for the exec  (NOT NULL)
+ *
+ * Returns: %0 or error on failure
+ */
+int apparmor_bprm_set_creds(struct linux_binprm *bprm)
+{
+       struct aa_task_cxt *cxt;
+       struct aa_profile *profile, *new_profile = NULL;
+       struct aa_namespace *ns;
+       char *buffer = NULL;
+       unsigned int state;
+       struct file_perms perms = {};
+       struct path_cond cond = {
+               bprm->file->f_path.dentry->d_inode->i_uid,
+               bprm->file->f_path.dentry->d_inode->i_mode
+       };
+       const char *name = NULL, *target = NULL, *info = NULL;
+       int error = cap_bprm_set_creds(bprm);
+       if (error)
+               return error;
+
+       if (bprm->cred_prepared)
+               return 0;
+
+       cxt = bprm->cred->security;
+       BUG_ON(!cxt);
+
+       profile = aa_get_profile(aa_newest_version(cxt->profile));
+       /*
+        * get the namespace from the replacement profile as replacement
+        * can change the namespace
+        */
+       ns = profile->ns;
+       state = profile->file.start;
+
+       /* buffer freed below, name is pointer into buffer */
+       error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer,
+                           &name);
+       if (error) {
+               if (profile->flags &
+                   (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
+                       error = 0;
+               info = "Exec failed name resolution";
+               name = bprm->filename;
+               goto audit;
+       }
+
+       /* Test for onexec first as onexec directives override other
+        * x transitions.
+        */
+       if (unconfined(profile)) {
+               /* unconfined task */
+               if (cxt->onexec)
+                       /* change_profile on exec already been granted */
+                       new_profile = aa_get_profile(cxt->onexec);
+               else
+                       new_profile = find_attach(ns, &ns->base.profiles, name);
+               if (!new_profile)
+                       goto cleanup;
+               goto apply;
+       }
+
+       /* find exec permissions for name */
+       state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
+       if (cxt->onexec) {
+               struct file_perms cp;
+               info = "change_profile onexec";
+               if (!(perms.allow & AA_MAY_ONEXEC))
+                       goto audit;
+
+               /* test if this exec can be paired with change_profile onexec.
+                * onexec permission is linked to exec with a standard pairing
+                * exec\0change_profile
+                */
+               state = aa_dfa_null_transition(profile->file.dfa, state);
+               cp = change_profile_perms(profile, cxt->onexec->ns, name,
+                                         AA_MAY_ONEXEC, state);
+
+               if (!(cp.allow & AA_MAY_ONEXEC))
+                       goto audit;
+               new_profile = aa_get_profile(aa_newest_version(cxt->onexec));
+               goto apply;
+       }
+
+       if (perms.allow & MAY_EXEC) {
+               /* exec permission determine how to transition */
+               new_profile = x_to_profile(profile, name, perms.xindex);
+               if (!new_profile) {
+                       if (perms.xindex & AA_X_INHERIT) {
+                               /* (p|c|n)ix - don't change profile but do
+                                * use the newest version, which was picked
+                                * up above when getting profile
+                                */
+                               info = "ix fallback";
+                               new_profile = aa_get_profile(profile);
+                               goto x_clear;
+                       } else if (perms.xindex & AA_X_UNCONFINED) {
+                               new_profile = aa_get_profile(ns->unconfined);
+                               info = "ux fallback";
+                       } else {
+                               error = -ENOENT;
+                               info = "profile not found";
+                       }
+               }
+       } else if (COMPLAIN_MODE(profile)) {
+               /* no exec permission - are we in learning mode */
+               new_profile = aa_new_null_profile(profile, 0);
+               if (!new_profile) {
+                       error = -ENOMEM;
+                       info = "could not create null profile";
+               } else {
+                       error = -EACCES;
+                       target = new_profile->base.hname;
+               }
+               perms.xindex |= AA_X_UNSAFE;
+       } else
+               /* fail exec */
+               error = -EACCES;
+
+       if (!new_profile)
+               goto audit;
+
+       if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+               /* FIXME: currently don't mediate shared state */
+               ;
+       }
+
+       if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+               error = may_change_ptraced_domain(current, new_profile);
+               if (error) {
+                       aa_put_profile(new_profile);
+                       goto audit;
+               }
+       }
+
+       /* Determine if secure exec is needed.
+        * Can be at this point for the following reasons:
+        * 1. unconfined switching to confined
+        * 2. confined switching to different confinement
+        * 3. confined switching to unconfined
+        *
+        * Cases 2 and 3 are marked as requiring secure exec
+        * (unless policy specified "unsafe exec")
+        *
+        * bprm->unsafe is used to cache the AA_X_UNSAFE permission
+        * to avoid having to recompute in secureexec
+        */
+       if (!(perms.xindex & AA_X_UNSAFE)) {
+               AA_DEBUG("scrubbing environment variables for %s profile=%s\n",
+                        name, new_profile->base.hname);
+               bprm->unsafe |= AA_SECURE_X_NEEDED;
+       }
+apply:
+       target = new_profile->base.hname;
+       /* when transitioning profiles clear unsafe personality bits */
+       bprm->per_clear |= PER_CLEAR_ON_SETID;
+
+x_clear:
+       aa_put_profile(cxt->profile);
+       /* transfer new profile reference will be released when cxt is freed */
+       cxt->profile = new_profile;
+
+       /* clear out all temporary/transitional state from the context */
+       aa_put_profile(cxt->previous);
+       aa_put_profile(cxt->onexec);
+       cxt->previous = NULL;
+       cxt->onexec = NULL;
+       cxt->token = 0;
+
+audit:
+       error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
+                             name, target, cond.uid, info, error);
+
+cleanup:
+       aa_put_profile(profile);
+       kfree(buffer);
+
+       return error;
+}
+
+/**
+ * apparmor_bprm_secureexec - determine if secureexec is needed
+ * @bprm: binprm for exec  (NOT NULL)
+ *
+ * Returns: %1 if secureexec is needed else %0
+ */
+int apparmor_bprm_secureexec(struct linux_binprm *bprm)
+{
+       int ret = cap_bprm_secureexec(bprm);
+
+       /* the decision to use secure exec is computed in set_creds
+        * and stored in bprm->unsafe.
+        */
+       if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
+               ret = 1;
+
+       return ret;
+}
+
+/**
+ * apparmor_bprm_committing_creds - do task cleanup on committing new creds
+ * @bprm: binprm for the exec  (NOT NULL)
+ */
+void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
+{
+       struct aa_profile *profile = __aa_current_profile();
+       struct aa_task_cxt *new_cxt = bprm->cred->security;
+
+       /* bail out if unconfined or not changing profile */
+       if ((new_cxt->profile == profile) ||
+           (unconfined(new_cxt->profile)))
+               return;
+
+       current->pdeath_signal = 0;
+
+       /* reset soft limits and set hard limits for the new profile */
+       __aa_transition_rlimits(profile, new_cxt->profile);
+}
+
+/**
+ * apparmor_bprm_commited_cred - do cleanup after new creds committed
+ * @bprm: binprm for the exec  (NOT NULL)
+ */
+void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
+{
+       /* TODO: cleanup signals - ipc mediation */
+       return;
+}
+
+/*
+ * Functions for self directed profile change
+ */
+
+/**
+ * new_compound_name - create an hname with @n2 appended to @n1
+ * @n1: base of hname  (NOT NULL)
+ * @n2: name to append (NOT NULL)
+ *
+ * Returns: new name or NULL on error
+ */
+static char *new_compound_name(const char *n1, const char *n2)
+{
+       char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL);
+       if (name)
+               sprintf(name, "%s//%s", n1, n2);
+       return name;
+}
+
+/**
+ * aa_change_hat - change hat to/from subprofile
+ * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
+ * @count: number of hat names in @hats
+ * @token: magic value to validate the hat change
+ * @permtest: true if this is just a permission test
+ *
+ * Change to the first profile specified in @hats that exists, and store
+ * the @hat_magic in the current task context.  If the count == 0 and the
+ * @token matches that stored in the current task context, return to the
+ * top level profile.
+ *
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
+{
+       const struct cred *cred;
+       struct aa_task_cxt *cxt;
+       struct aa_profile *profile, *previous_profile, *hat = NULL;
+       char *name = NULL;
+       int i;
+       struct file_perms perms = {};
+       const char *target = NULL, *info = NULL;
+       int error = 0;
+
+       /* released below */
+       cred = get_current_cred();
+       cxt = cred->security;
+       profile = aa_cred_profile(cred);
+       previous_profile = cxt->previous;
+
+       if (unconfined(profile)) {
+               info = "unconfined";
+               error = -EPERM;
+               goto audit;
+       }
+
+       if (count) {
+               /* attempting to change into a new hat or switch to a sibling */
+               struct aa_profile *root;
+               root = PROFILE_IS_HAT(profile) ? profile->parent : profile;
+
+               /* find first matching hat */
+               for (i = 0; i < count && !hat; i++)
+                       /* released below */
+                       hat = aa_find_child(root, hats[i]);
+               if (!hat) {
+                       if (!COMPLAIN_MODE(root) || permtest) {
+                               if (list_empty(&root->base.profiles))
+                                       error = -ECHILD;
+                               else
+                                       error = -ENOENT;
+                               goto out;
+                       }
+
+                       /*
+                        * In complain mode and failed to match any hats.
+                        * Audit the failure is based off of the first hat
+                        * supplied.  This is done due how userspace
+                        * interacts with change_hat.
+                        *
+                        * TODO: Add logging of all failed hats
+                        */
+
+                       /* freed below */
+                       name = new_compound_name(root->base.hname, hats[0]);
+                       target = name;
+                       /* released below */
+                       hat = aa_new_null_profile(profile, 1);
+                       if (!hat) {
+                               info = "failed null profile create";
+                               error = -ENOMEM;
+                               goto audit;
+                       }
+               } else {
+                       target = hat->base.hname;
+                       if (!PROFILE_IS_HAT(hat)) {
+                               info = "target not hat";
+                               error = -EPERM;
+                               goto audit;
+                       }
+               }
+
+               error = may_change_ptraced_domain(current, hat);
+               if (error) {
+                       info = "ptraced";
+                       error = -EPERM;
+                       goto audit;
+               }
+
+               if (!permtest) {
+                       error = aa_set_current_hat(hat, token);
+                       if (error == -EACCES)
+                               /* kill task in case of brute force attacks */
+                               perms.kill = AA_MAY_CHANGEHAT;
+                       else if (name && !error)
+                               /* reset error for learning of new hats */
+                               error = -ENOENT;
+               }
+       } else if (previous_profile) {
+               /* Return to saved profile.  Kill task if restore fails
+                * to avoid brute force attacks
+                */
+               target = previous_profile->base.hname;
+               error = aa_restore_previous_profile(token);
+               perms.kill = AA_MAY_CHANGEHAT;
+       } else
+               /* ignore restores when there is no saved profile */
+               goto out;
+
+audit:
+       if (!permtest)
+               error = aa_audit_file(profile, &perms, GFP_KERNEL,
+                                     OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL,
+                                     target, 0, info, error);
+
+out:
+       aa_put_profile(hat);
+       kfree(name);
+       put_cred(cred);
+
+       return error;
+}
+
+/**
+ * aa_change_profile - perform a one-way profile transition
+ * @ns_name: name of the profile namespace to change to (MAYBE NULL)
+ * @hname: name of profile to change to (MAYBE NULL)
+ * @onexec: whether this transition is to take place immediately or at exec
+ * @permtest: true if this is just a permission test
+ *
+ * Change to new profile @name.  Unlike with hats, there is no way
+ * to change back.  If @name isn't specified the current profile name is
+ * used.
+ * If @onexec then the transition is delayed until
+ * the next exec.
+ *
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
+                     bool permtest)
+{
+       const struct cred *cred;
+       struct aa_task_cxt *cxt;
+       struct aa_profile *profile, *target = NULL;
+       struct aa_namespace *ns = NULL;
+       struct file_perms perms = {};
+       const char *name = NULL, *info = NULL;
+       int op, error = 0;
+       u32 request;
+
+       if (!hname && !ns_name)
+               return -EINVAL;
+
+       if (onexec) {
+               request = AA_MAY_ONEXEC;
+               op = OP_CHANGE_ONEXEC;
+       } else {
+               request = AA_MAY_CHANGE_PROFILE;
+               op = OP_CHANGE_PROFILE;
+       }
+
+       cred = get_current_cred();
+       cxt = cred->security;
+       profile = aa_cred_profile(cred);
+
+       if (ns_name) {
+               /* released below */
+               ns = aa_find_namespace(profile->ns, ns_name);
+               if (!ns) {
+                       /* we don't create new namespace in complain mode */
+                       name = ns_name;
+                       info = "namespace not found";
+                       error = -ENOENT;
+                       goto audit;
+               }
+       } else
+               /* released below */
+               ns = aa_get_namespace(profile->ns);
+
+       /* if the name was not specified, use the name of the current profile */
+       if (!hname) {
+               if (unconfined(profile))
+                       hname = ns->unconfined->base.hname;
+               else
+                       hname = profile->base.hname;
+       }
+
+       perms = change_profile_perms(profile, ns, hname, request,
+                                    profile->file.start);
+       if (!(perms.allow & request)) {
+               error = -EACCES;
+               goto audit;
+       }
+
+       /* released below */
+       target = aa_lookup_profile(ns, hname);
+       if (!target) {
+               info = "profile not found";
+               error = -ENOENT;
+               if (permtest || !COMPLAIN_MODE(profile))
+                       goto audit;
+               /* released below */
+               target = aa_new_null_profile(profile, 0);
+               if (!target) {
+                       info = "failed null profile create";
+                       error = -ENOMEM;
+                       goto audit;
+               }
+       }
+
+       /* check if tracing task is allowed to trace target domain */
+       error = may_change_ptraced_domain(current, target);
+       if (error) {
+               info = "ptrace prevents transition";
+               goto audit;
+       }
+
+       if (permtest)
+               goto audit;
+
+       if (onexec)
+               error = aa_set_current_onexec(target);
+       else
+               error = aa_replace_current_profile(target);
+
+audit:
+       if (!permtest)
+               error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
+                                     name, hname, 0, info, error);
+
+       aa_put_namespace(ns);
+       aa_put_profile(target);
+       put_cred(cred);
+
+       return error;
+}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
new file mode 100644 (file)
index 0000000..7312db7
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+struct file_perms nullperms;
+
+
+/**
+ * audit_file_mask - convert mask to permission string
+ * @buffer: buffer to write string to (NOT NULL)
+ * @mask: permission mask to convert
+ */
+static void audit_file_mask(struct audit_buffer *ab, u32 mask)
+{
+       char str[10];
+
+       char *m = str;
+
+       if (mask & AA_EXEC_MMAP)
+               *m++ = 'm';
+       if (mask & (MAY_READ | AA_MAY_META_READ))
+               *m++ = 'r';
+       if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD |
+                   AA_MAY_CHOWN))
+               *m++ = 'w';
+       else if (mask & MAY_APPEND)
+               *m++ = 'a';
+       if (mask & AA_MAY_CREATE)
+               *m++ = 'c';
+       if (mask & AA_MAY_DELETE)
+               *m++ = 'd';
+       if (mask & AA_MAY_LINK)
+               *m++ = 'l';
+       if (mask & AA_MAY_LOCK)
+               *m++ = 'k';
+       if (mask & MAY_EXEC)
+               *m++ = 'x';
+       *m = '\0';
+
+       audit_log_string(ab, str);
+}
+
+/**
+ * file_audit_cb - call back for file specific audit fields
+ * @ab: audit_buffer  (NOT NULL)
+ * @va: audit struct to audit values of  (NOT NULL)
+ */
+static void file_audit_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+       uid_t fsuid = current_fsuid();
+
+       if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+               audit_log_format(ab, " requested_mask=");
+               audit_file_mask(ab, sa->aad.fs.request);
+       }
+       if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
+               audit_log_format(ab, " denied_mask=");
+               audit_file_mask(ab, sa->aad.fs.denied);
+       }
+       if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+               audit_log_format(ab, " fsuid=%d", fsuid);
+               audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
+       }
+
+       if (sa->aad.fs.target) {
+               audit_log_format(ab, " target=");
+               audit_log_untrustedstring(ab, sa->aad.fs.target);
+       }
+}
+
+/**
+ * aa_audit_file - handle the auditing of file operations
+ * @profile: the profile being enforced  (NOT NULL)
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated
+ * @request: permissions requested
+ * @name: name of object being mediated (MAYBE NULL)
+ * @target: name of target (MAYBE NULL)
+ * @ouid: object uid
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+                 gfp_t gfp, int op, u32 request, const char *name,
+                 const char *target, uid_t ouid, const char *info, int error)
+{
+       int type = AUDIT_APPARMOR_AUTO;
+       struct common_audit_data sa;
+       COMMON_AUDIT_DATA_INIT(&sa, NONE);
+       sa.aad.op = op,
+       sa.aad.fs.request = request;
+       sa.aad.name = name;
+       sa.aad.fs.target = target;
+       sa.aad.fs.ouid = ouid;
+       sa.aad.info = info;
+       sa.aad.error = error;
+
+       if (likely(!sa.aad.error)) {
+               u32 mask = perms->audit;
+
+               if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+                       mask = 0xffff;
+
+               /* mask off perms that are not being force audited */
+               sa.aad.fs.request &= mask;
+
+               if (likely(!sa.aad.fs.request))
+                       return 0;
+               type = AUDIT_APPARMOR_AUDIT;
+       } else {
+               /* only report permissions that were denied */
+               sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
+
+               if (sa.aad.fs.request & perms->kill)
+                       type = AUDIT_APPARMOR_KILL;
+
+               /* quiet known rejects, assumes quiet and kill do not overlap */
+               if ((sa.aad.fs.request & perms->quiet) &&
+                   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+                   AUDIT_MODE(profile) != AUDIT_ALL)
+                       sa.aad.fs.request &= ~perms->quiet;
+
+               if (!sa.aad.fs.request)
+                       return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
+       }
+
+       sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
+       return aa_audit(type, profile, gfp, &sa, file_audit_cb);
+}
+
+/**
+ * map_old_perms - map old file perms layout to the new layout
+ * @old: permission set in old mapping
+ *
+ * Returns: new permission mapping
+ */
+static u32 map_old_perms(u32 old)
+{
+       u32 new = old & 0xf;
+       if (old & MAY_READ)
+               new |= AA_MAY_META_READ;
+       if (old & MAY_WRITE)
+               new |= AA_MAY_META_WRITE | AA_MAY_CREATE | AA_MAY_DELETE |
+                       AA_MAY_CHMOD | AA_MAY_CHOWN;
+       if (old & 0x10)
+               new |= AA_MAY_LINK;
+       /* the old mapping lock and link_subset flags where overlaid
+        * and use was determined by part of a pair that they were in
+        */
+       if (old & 0x20)
+               new |= AA_MAY_LOCK | AA_LINK_SUBSET;
+       if (old & 0x40) /* AA_EXEC_MMAP */
+               new |= AA_EXEC_MMAP;
+
+       new |= AA_MAY_META_READ;
+
+       return new;
+}
+
+/**
+ * compute_perms - convert dfa compressed perms to internal perms
+ * @dfa: dfa to compute perms for   (NOT NULL)
+ * @state: state in dfa
+ * @cond:  conditions to consider  (NOT NULL)
+ *
+ * TODO: convert from dfa + state to permission entry, do computation conversion
+ *       at load time.
+ *
+ * Returns: computed permission set
+ */
+static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
+                                      struct path_cond *cond)
+{
+       struct file_perms perms;
+
+       /* FIXME: change over to new dfa format
+        * currently file perms are encoded in the dfa, new format
+        * splits the permissions from the dfa.  This mapping can be
+        * done at profile load
+        */
+       perms.kill = 0;
+
+       if (current_fsuid() == cond->uid) {
+               perms.allow = map_old_perms(dfa_user_allow(dfa, state));
+               perms.audit = map_old_perms(dfa_user_audit(dfa, state));
+               perms.quiet = map_old_perms(dfa_user_quiet(dfa, state));
+               perms.xindex = dfa_user_xindex(dfa, state);
+       } else {
+               perms.allow = map_old_perms(dfa_other_allow(dfa, state));
+               perms.audit = map_old_perms(dfa_other_audit(dfa, state));
+               perms.quiet = map_old_perms(dfa_other_quiet(dfa, state));
+               perms.xindex = dfa_other_xindex(dfa, state);
+       }
+
+       /* change_profile wasn't determined by ownership in old mapping */
+       if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
+               perms.allow |= AA_MAY_CHANGE_PROFILE;
+
+       return perms;
+}
+
+/**
+ * aa_str_perms - find permission that match @name
+ * @dfa: to match against  (MAYBE NULL)
+ * @state: state to start matching in
+ * @name: string to match against dfa  (NOT NULL)
+ * @cond: conditions to consider for permission set computation  (NOT NULL)
+ * @perms: Returns - the permissions found when matching @name
+ *
+ * Returns: the final state in @dfa when beginning @start and walking @name
+ */
+unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
+                         const char *name, struct path_cond *cond,
+                         struct file_perms *perms)
+{
+       unsigned int state;
+       if (!dfa) {
+               *perms = nullperms;
+               return DFA_NOMATCH;
+       }
+
+       state = aa_dfa_match(dfa, start, name);
+       *perms = compute_perms(dfa, state, cond);
+
+       return state;
+}
+
+/**
+ * is_deleted - test if a file has been completely unlinked
+ * @dentry: dentry of file to test for deletion  (NOT NULL)
+ *
+ * Returns: %1 if deleted else %0
+ */
+static inline bool is_deleted(struct dentry *dentry)
+{
+       if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0)
+               return 1;
+       return 0;
+}
+
+/**
+ * aa_path_perm - do permissions check & audit for @path
+ * @op: operation being checked
+ * @profile: profile being enforced  (NOT NULL)
+ * @path: path to check permissions of  (NOT NULL)
+ * @flags: any additional path flags beyond what the profile specifies
+ * @request: requested permissions
+ * @cond: conditional info for this request  (NOT NULL)
+ *
+ * Returns: %0 else error if access denied or other error
+ */
+int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+                int flags, u32 request, struct path_cond *cond)
+{
+       char *buffer = NULL;
+       struct file_perms perms = {};
+       const char *name, *info = NULL;
+       int error;
+
+       flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
+       error = aa_get_name(path, flags, &buffer, &name);
+       if (error) {
+               if (error == -ENOENT && is_deleted(path->dentry)) {
+                       /* Access to open files that are deleted are
+                        * give a pass (implicit delegation)
+                        */
+                       error = 0;
+                       perms.allow = request;
+               } else if (error == -ENOENT)
+                       info = "Failed name lookup - deleted entry";
+               else if (error == -ESTALE)
+                       info = "Failed name lookup - disconnected path";
+               else if (error == -ENAMETOOLONG)
+                       info = "Failed name lookup - name too long";
+               else
+                       info = "Failed name lookup";
+       } else {
+               aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
+                            &perms);
+               if (request & ~perms.allow)
+                       error = -EACCES;
+       }
+       error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
+                             NULL, cond->uid, info, error);
+       kfree(buffer);
+
+       return error;
+}
+
+/**
+ * xindex_is_subset - helper for aa_path_link
+ * @link: link permission set
+ * @target: target permission set
+ *
+ * test target x permissions are equal OR a subset of link x permissions
+ * this is done as part of the subset test, where a hardlink must have
+ * a subset of permissions that the target has.
+ *
+ * Returns: %1 if subset else %0
+ */
+static inline bool xindex_is_subset(u32 link, u32 target)
+{
+       if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
+           ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
+               return 0;
+
+       return 1;
+}
+
+/**
+ * aa_path_link - Handle hard link permission check
+ * @profile: the profile being enforced  (NOT NULL)
+ * @old_dentry: the target dentry  (NOT NULL)
+ * @new_dir: directory the new link will be created in  (NOT NULL)
+ * @new_dentry: the link being created  (NOT NULL)
+ *
+ * Handle the permission test for a link & target pair.  Permission
+ * is encoded as a pair where the link permission is determined
+ * first, and if allowed, the target is tested.  The target test
+ * is done from the point of the link match (not start of DFA)
+ * making the target permission dependent on the link permission match.
+ *
+ * The subset test if required forces that permissions granted
+ * on link are a subset of the permission granted to target.
+ *
+ * Returns: %0 if allowed else error
+ */
+int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+                struct path *new_dir, struct dentry *new_dentry)
+{
+       struct path link = { new_dir->mnt, new_dentry };
+       struct path target = { new_dir->mnt, old_dentry };
+       struct path_cond cond = {
+               old_dentry->d_inode->i_uid,
+               old_dentry->d_inode->i_mode
+       };
+       char *buffer = NULL, *buffer2 = NULL;
+       const char *lname, *tname = NULL, *info = NULL;
+       struct file_perms lperms, perms;
+       u32 request = AA_MAY_LINK;
+       unsigned int state;
+       int error;
+
+       lperms = nullperms;
+
+       /* buffer freed below, lname is pointer in buffer */
+       error = aa_get_name(&link, profile->path_flags, &buffer, &lname);
+       if (error)
+               goto audit;
+
+       /* buffer2 freed below, tname is pointer in buffer2 */
+       error = aa_get_name(&target, profile->path_flags, &buffer2, &tname);
+       if (error)
+               goto audit;
+
+       error = -EACCES;
+       /* aa_str_perms - handles the case of the dfa being NULL */
+       state = aa_str_perms(profile->file.dfa, profile->file.start, lname,
+                            &cond, &lperms);
+
+       if (!(lperms.allow & AA_MAY_LINK))
+               goto audit;
+
+       /* test to see if target can be paired with link */
+       state = aa_dfa_null_transition(profile->file.dfa, state);
+       aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
+
+       /* force audit/quiet masks for link are stored in the second entry
+        * in the link pair.
+        */
+       lperms.audit = perms.audit;
+       lperms.quiet = perms.quiet;
+       lperms.kill = perms.kill;
+
+       if (!(perms.allow & AA_MAY_LINK)) {
+               info = "target restricted";
+               goto audit;
+       }
+
+       /* done if link subset test is not required */
+       if (!(perms.allow & AA_LINK_SUBSET))
+               goto done_tests;
+
+       /* Do link perm subset test requiring allowed permission on link are a
+        * subset of the allowed permissions on target.
+        */
+       aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond,
+                    &perms);
+
+       /* AA_MAY_LINK is not considered in the subset test */
+       request = lperms.allow & ~AA_MAY_LINK;
+       lperms.allow &= perms.allow | AA_MAY_LINK;
+
+       request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
+       if (request & ~lperms.allow) {
+               goto audit;
+       } else if ((lperms.allow & MAY_EXEC) &&
+                  !xindex_is_subset(lperms.xindex, perms.xindex)) {
+               lperms.allow &= ~MAY_EXEC;
+               request |= MAY_EXEC;
+               info = "link not subset of target";
+               goto audit;
+       }
+
+done_tests:
+       error = 0;
+
+audit:
+       error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
+                             lname, tname, cond.uid, info, error);
+       kfree(buffer);
+       kfree(buffer2);
+
+       return error;
+}
+
+/**
+ * aa_file_perm - do permission revalidation check & audit for @file
+ * @op: operation being checked
+ * @profile: profile being enforced   (NOT NULL)
+ * @file: file to revalidate access permissions on  (NOT NULL)
+ * @request: requested permissions
+ *
+ * Returns: %0 if access allowed else error
+ */
+int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+                u32 request)
+{
+       struct path_cond cond = {
+               .uid = file->f_path.dentry->d_inode->i_uid,
+               .mode = file->f_path.dentry->d_inode->i_mode
+       };
+
+       return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
+                           request, &cond);
+}
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
new file mode 100644 (file)
index 0000000..38ccaea
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic global and lib definitions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __APPARMOR_H
+#define __APPARMOR_H
+
+#include <linux/fs.h>
+
+#include "match.h"
+
+/* Control parameters settable through module/boot flags */
+extern enum audit_mode aa_g_audit;
+extern int aa_g_audit_header;
+extern int aa_g_debug;
+extern int aa_g_lock_policy;
+extern int aa_g_logsyscall;
+extern int aa_g_paranoid_load;
+extern unsigned int aa_g_path_max;
+
+/*
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
+ * which is not related to profile accesses.
+ */
+
+#define AA_DEBUG(fmt, args...)                                         \
+       do {                                                            \
+               if (aa_g_debug && printk_ratelimit())                   \
+                       printk(KERN_DEBUG "AppArmor: " fmt, ##args);    \
+       } while (0)
+
+#define AA_ERROR(fmt, args...)                                         \
+       do {                                                            \
+               if (printk_ratelimit())                                 \
+                       printk(KERN_ERR "AppArmor: " fmt, ##args);      \
+       } while (0)
+
+/* Flag indicating whether initialization completed */
+extern int apparmor_initialized __initdata;
+
+/* fn's in lib */
+char *aa_split_fqname(char *args, char **ns_name);
+void aa_info_message(const char *str);
+void *kvmalloc(size_t size);
+void kvfree(void *buffer);
+
+
+/**
+ * aa_strneq - compare null terminated @str to a non null terminated substring
+ * @str: a null terminated string
+ * @sub: a substring, not necessarily null terminated
+ * @len: length of @sub to compare
+ *
+ * The @str string must be full consumed for this to be considered a match
+ */
+static inline bool aa_strneq(const char *str, const char *sub, int len)
+{
+       return !strncmp(str, sub, len) && !str[len];
+}
+
+/**
+ * aa_dfa_null_transition - step to next state after null character
+ * @dfa: the dfa to match against
+ * @start: the state of the dfa to start matching in
+ *
+ * aa_dfa_null_transition transitions to the next state after a null
+ * character which is not used in standard matching and is only
+ * used to separate pairs.
+ */
+static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
+                                                 unsigned int start)
+{
+       /* the null transition only needs the string's null terminator byte */
+       return aa_dfa_match_len(dfa, start, "", 1);
+}
+
+static inline bool mediated_filesystem(struct inode *inode)
+{
+       return !(inode->i_sb->s_flags & MS_NOUSER);
+}
+
+#endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
new file mode 100644 (file)
index 0000000..cb1e93a
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor filesystem definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_APPARMORFS_H
+#define __AA_APPARMORFS_H
+
+extern void __init aa_destroy_aafs(void);
+
+#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
new file mode 100644 (file)
index 0000000..1951786
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor auditing function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_AUDIT_H
+#define __AA_AUDIT_H
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/lsm_audit.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "file.h"
+
+struct aa_profile;
+
+extern const char *audit_mode_names[];
+#define AUDIT_MAX_INDEX 5
+
+#define AUDIT_APPARMOR_AUTO 0  /* auto choose audit message type */
+
+enum audit_mode {
+       AUDIT_NORMAL,           /* follow normal auditing of accesses */
+       AUDIT_QUIET_DENIED,     /* quiet all denied access messages */
+       AUDIT_QUIET,            /* quiet all messages */
+       AUDIT_NOQUIET,          /* do not quiet audit messages */
+       AUDIT_ALL               /* audit all accesses */
+};
+
+enum audit_type {
+       AUDIT_APPARMOR_AUDIT,
+       AUDIT_APPARMOR_ALLOWED,
+       AUDIT_APPARMOR_DENIED,
+       AUDIT_APPARMOR_HINT,
+       AUDIT_APPARMOR_STATUS,
+       AUDIT_APPARMOR_ERROR,
+       AUDIT_APPARMOR_KILL
+};
+
+extern const char *op_table[];
+enum aa_ops {
+       OP_NULL,
+
+       OP_SYSCTL,
+       OP_CAPABLE,
+
+       OP_UNLINK,
+       OP_MKDIR,
+       OP_RMDIR,
+       OP_MKNOD,
+       OP_TRUNC,
+       OP_LINK,
+       OP_SYMLINK,
+       OP_RENAME_SRC,
+       OP_RENAME_DEST,
+       OP_CHMOD,
+       OP_CHOWN,
+       OP_GETATTR,
+       OP_OPEN,
+
+       OP_FPERM,
+       OP_FLOCK,
+       OP_FMMAP,
+       OP_FMPROT,
+
+       OP_CREATE,
+       OP_POST_CREATE,
+       OP_BIND,
+       OP_CONNECT,
+       OP_LISTEN,
+       OP_ACCEPT,
+       OP_SENDMSG,
+       OP_RECVMSG,
+       OP_GETSOCKNAME,
+       OP_GETPEERNAME,
+       OP_GETSOCKOPT,
+       OP_SETSOCKOPT,
+       OP_SOCK_SHUTDOWN,
+
+       OP_PTRACE,
+
+       OP_EXEC,
+       OP_CHANGE_HAT,
+       OP_CHANGE_PROFILE,
+       OP_CHANGE_ONEXEC,
+
+       OP_SETPROCATTR,
+       OP_SETRLIMIT,
+
+       OP_PROF_REPL,
+       OP_PROF_LOAD,
+       OP_PROF_RM,
+};
+
+
+/* define a short hand for apparmor_audit_data portion of common_audit_data */
+#define aad apparmor_audit_data
+
+void aa_audit_msg(int type, struct common_audit_data *sa,
+                 void (*cb) (struct audit_buffer *, void *));
+int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
+            struct common_audit_data *sa,
+            void (*cb) (struct audit_buffer *, void *));
+
+static inline int complain_error(int error)
+{
+       if (error == -EPERM || error == -EACCES)
+               return 0;
+       return error;
+}
+
+#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
new file mode 100644 (file)
index 0000000..c24d295
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor capability mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_CAPABILITY_H
+#define __AA_CAPABILITY_H
+
+#include <linux/sched.h>
+
+struct aa_profile;
+
+/* aa_caps - confinement data for capabilities
+ * @allowed: capabilities mask
+ * @audit: caps that are to be audited
+ * @quiet: caps that should not be audited
+ * @kill: caps that when requested will result in the task being killed
+ * @extended: caps that are subject finer grained mediation
+ */
+struct aa_caps {
+       kernel_cap_t allow;
+       kernel_cap_t audit;
+       kernel_cap_t quiet;
+       kernel_cap_t kill;
+       kernel_cap_t extended;
+};
+
+int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
+              int audit);
+
+static inline void aa_free_cap_rules(struct aa_caps *caps)
+{
+       /* NOP */
+}
+
+#endif /* __AA_CAPBILITY_H */
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
new file mode 100644 (file)
index 0000000..a9cbee4
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor contexts used to associate "labels" to objects.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_CONTEXT_H
+#define __AA_CONTEXT_H
+
+#include <linux/cred.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "policy.h"
+
+/* struct aa_file_cxt - the AppArmor context the file was opened in
+ * @perms: the permission the file was opened with
+ *
+ * The file_cxt could currently be directly stored in file->f_security
+ * as the profile reference is now stored in the f_cred.  However the
+ * cxt struct will expand in the future so we keep the struct.
+ */
+struct aa_file_cxt {
+       u16 allow;
+};
+
+/**
+ * aa_alloc_file_context - allocate file_cxt
+ * @gfp: gfp flags for allocation
+ *
+ * Returns: file_cxt or NULL on failure
+ */
+static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
+{
+       return kzalloc(sizeof(struct aa_file_cxt), gfp);
+}
+
+/**
+ * aa_free_file_context - free a file_cxt
+ * @cxt: file_cxt to free  (MAYBE_NULL)
+ */
+static inline void aa_free_file_context(struct aa_file_cxt *cxt)
+{
+       if (cxt)
+               kzfree(cxt);
+}
+
+/**
+ * struct aa_task_cxt - primary label for confined tasks
+ * @profile: the current profile   (NOT NULL)
+ * @exec: profile to transition to on next exec  (MAYBE NULL)
+ * @previous: profile the task may return to     (MAYBE NULL)
+ * @token: magic value the task must know for returning to @previous_profile
+ *
+ * Contains the task's current profile (which could change due to
+ * change_hat).  Plus the hat_magic needed during change_hat.
+ *
+ * TODO: make so a task can be confined by a stack of contexts
+ */
+struct aa_task_cxt {
+       struct aa_profile *profile;
+       struct aa_profile *onexec;
+       struct aa_profile *previous;
+       u64 token;
+};
+
+struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
+void aa_free_task_context(struct aa_task_cxt *cxt);
+void aa_dup_task_context(struct aa_task_cxt *new,
+                        const struct aa_task_cxt *old);
+int aa_replace_current_profile(struct aa_profile *profile);
+int aa_set_current_onexec(struct aa_profile *profile);
+int aa_set_current_hat(struct aa_profile *profile, u64 token);
+int aa_restore_previous_profile(u64 cookie);
+
+/**
+ * __aa_task_is_confined - determine if @task has any confinement
+ * @task: task to check confinement of  (NOT NULL)
+ *
+ * If @task != current needs to be called in RCU safe critical section
+ */
+static inline bool __aa_task_is_confined(struct task_struct *task)
+{
+       struct aa_task_cxt *cxt = __task_cred(task)->security;
+
+       BUG_ON(!cxt || !cxt->profile);
+       if (unconfined(aa_newest_version(cxt->profile)))
+               return 0;
+
+       return 1;
+}
+
+/**
+ * aa_cred_profile - obtain cred's profiles
+ * @cred: cred to obtain profiles from  (NOT NULL)
+ *
+ * Returns: confining profile
+ *
+ * does NOT increment reference count
+ */
+static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
+{
+       struct aa_task_cxt *cxt = cred->security;
+       BUG_ON(!cxt || !cxt->profile);
+       return aa_newest_version(cxt->profile);
+}
+
+/**
+ * __aa_current_profile - find the current tasks confining profile
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * This fn will not update the tasks cred to the most up to date version
+ * of the profile so it is safe to call when inside of locks.
+ */
+static inline struct aa_profile *__aa_current_profile(void)
+{
+       return aa_cred_profile(current_cred());
+}
+
+/**
+ * aa_current_profile - find the current tasks confining profile and do updates
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * This fn will update the tasks cred structure if the profile has been
+ * replaced.  Not safe to call inside locks
+ */
+static inline struct aa_profile *aa_current_profile(void)
+{
+       const struct aa_task_cxt *cxt = current_cred()->security;
+       struct aa_profile *profile;
+       BUG_ON(!cxt || !cxt->profile);
+
+       profile = aa_newest_version(cxt->profile);
+       /*
+        * Whether or not replacement succeeds, use newest profile so
+        * there is no need to update it after replacement.
+        */
+       if (unlikely((cxt->profile != profile)))
+               aa_replace_current_profile(profile);
+
+       return profile;
+}
+
+#endif /* __AA_CONTEXT_H */
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
new file mode 100644 (file)
index 0000000..de04464
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security domain transition function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/binfmts.h>
+#include <linux/types.h>
+
+#ifndef __AA_DOMAIN_H
+#define __AA_DOMAIN_H
+
+struct aa_domain {
+       int size;
+       char **table;
+};
+
+int apparmor_bprm_set_creds(struct linux_binprm *bprm);
+int apparmor_bprm_secureexec(struct linux_binprm *bprm);
+void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
+void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
+
+void aa_free_domain_entries(struct aa_domain *domain);
+int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
+int aa_change_profile(const char *ns_name, const char *name, bool onexec,
+                     bool permtest);
+
+#endif /* __AA_DOMAIN_H */
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
new file mode 100644 (file)
index 0000000..be36fea
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_FILE_H
+#define __AA_FILE_H
+
+#include <linux/path.h>
+
+#include "domain.h"
+#include "match.h"
+
+struct aa_profile;
+
+/*
+ * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
+ * for profile permissions
+ */
+#define AA_MAY_CREATE                  0x0010
+#define AA_MAY_DELETE                  0x0020
+#define AA_MAY_META_WRITE              0x0040
+#define AA_MAY_META_READ               0x0080
+
+#define AA_MAY_CHMOD                   0x0100
+#define AA_MAY_CHOWN                   0x0200
+#define AA_MAY_LOCK                    0x0400
+#define AA_EXEC_MMAP                   0x0800
+
+#define AA_MAY_LINK                    0x1000
+#define AA_LINK_SUBSET                 AA_MAY_LOCK     /* overlaid */
+#define AA_MAY_ONEXEC                  0x40000000      /* exec allows onexec */
+#define AA_MAY_CHANGE_PROFILE          0x80000000
+#define AA_MAY_CHANGEHAT               0x80000000      /* ctrl auditing only */
+
+#define AA_AUDIT_FILE_MASK     (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
+                                AA_MAY_CREATE | AA_MAY_DELETE |        \
+                                AA_MAY_META_READ | AA_MAY_META_WRITE | \
+                                AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
+                                AA_EXEC_MMAP | AA_MAY_LINK)
+
+/*
+ * The xindex is broken into 3 parts
+ * - index - an index into either the exec name table or the variable table
+ * - exec type - which determines how the executable name and index are used
+ * - flags - which modify how the destination name is applied
+ */
+#define AA_X_INDEX_MASK                0x03ff
+
+#define AA_X_TYPE_MASK         0x0c00
+#define AA_X_TYPE_SHIFT                10
+#define AA_X_NONE              0x0000
+#define AA_X_NAME              0x0400  /* use executable name px */
+#define AA_X_TABLE             0x0800  /* use a specified name ->n# */
+
+#define AA_X_UNSAFE            0x1000
+#define AA_X_CHILD             0x2000  /* make >AA_X_NONE apply to children */
+#define AA_X_INHERIT           0x4000
+#define AA_X_UNCONFINED                0x8000
+
+/* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */
+#define AA_SECURE_X_NEEDED     0x8000
+
+/* need to make conditional which ones are being set */
+struct path_cond {
+       uid_t uid;
+       umode_t mode;
+};
+
+/* struct file_perms - file permission
+ * @allow: mask of permissions that are allowed
+ * @audit: mask of permissions to force an audit message for
+ * @quiet: mask of permissions to quiet audit messages for
+ * @kill: mask of permissions that when matched will kill the task
+ * @xindex: exec transition index if @allow contains MAY_EXEC
+ *
+ * The @audit and @queit mask should be mutually exclusive.
+ */
+struct file_perms {
+       u32 allow;
+       u32 audit;
+       u32 quiet;
+       u32 kill;
+       u16 xindex;
+};
+
+extern struct file_perms nullperms;
+
+#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
+
+/* FIXME: split perms from dfa and match this to description
+ *        also add delegation info.
+ */
+static inline u16 dfa_map_xindex(u16 mask)
+{
+       u16 old_index = (mask >> 10) & 0xf;
+       u16 index = 0;
+
+       if (mask & 0x100)
+               index |= AA_X_UNSAFE;
+       if (mask & 0x200)
+               index |= AA_X_INHERIT;
+       if (mask & 0x80)
+               index |= AA_X_UNCONFINED;
+
+       if (old_index == 1) {
+               index |= AA_X_UNCONFINED;
+       } else if (old_index == 2) {
+               index |= AA_X_NAME;
+       } else if (old_index == 3) {
+               index |= AA_X_NAME | AA_X_CHILD;
+       } else {
+               index |= AA_X_TABLE;
+               index |= old_index - 4;
+       }
+
+       return index;
+}
+
+/*
+ * map old dfa inline permissions to new format
+ */
+#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
+                                   ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
+#define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
+#define dfa_user_xindex(dfa, state) \
+       (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff))
+
+#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
+                                     0x7f) |                           \
+                                    ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
+#define dfa_other_quiet(dfa, state) \
+       ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
+#define dfa_other_xindex(dfa, state) \
+       dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
+
+int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+                 gfp_t gfp, int op, u32 request, const char *name,
+                 const char *target, uid_t ouid, const char *info, int error);
+
+/**
+ * struct aa_file_rules - components used for file rule permissions
+ * @dfa: dfa to match path names and conditionals against
+ * @perms: permission table indexed by the matched state accept entry of @dfa
+ * @trans: transition table for indexed by named x transitions
+ *
+ * File permission are determined by matching a path against @dfa and then
+ * then using the value of the accept entry for the matching state as
+ * an index into @perms.  If a named exec transition is required it is
+ * looked up in the transition table.
+ */
+struct aa_file_rules {
+       unsigned int start;
+       struct aa_dfa *dfa;
+       /* struct perms perms; */
+       struct aa_domain trans;
+       /* TODO: add delegate table */
+};
+
+unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
+                         const char *name, struct path_cond *cond,
+                         struct file_perms *perms);
+
+int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+                int flags, u32 request, struct path_cond *cond);
+
+int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+                struct path *new_dir, struct dentry *new_dentry);
+
+int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+                u32 request);
+
+static inline void aa_free_file_rules(struct aa_file_rules *rules)
+{
+       aa_put_dfa(rules->dfa);
+       aa_free_domain_entries(&rules->trans);
+}
+
+#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
+
+/* from namei.c */
+#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
+
+/**
+ * aa_map_file_perms - map file flags to AppArmor permissions
+ * @file: open file to map flags to AppArmor permissions
+ *
+ * Returns: apparmor permission set for the file
+ */
+static inline u32 aa_map_file_to_perms(struct file *file)
+{
+       int flags = MAP_OPEN_FLAGS(file->f_flags);
+       u32 perms = ACC_FMODE(file->f_mode);
+
+       if ((flags & O_APPEND) && (perms & MAY_WRITE))
+               perms = (perms & ~MAY_WRITE) | MAY_APPEND;
+       /* trunc implies write permission */
+       if (flags & O_TRUNC)
+               perms |= MAY_WRITE;
+       if (flags & O_CREAT)
+               perms |= AA_MAY_CREATE;
+
+       return perms;
+}
+
+#endif /* __AA_FILE_H */
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
new file mode 100644 (file)
index 0000000..aeda0fb
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor ipc mediation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_IPC_H
+#define __AA_IPC_H
+
+#include <linux/sched.h>
+
+struct aa_profile;
+
+int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
+                 struct aa_profile *tracee, unsigned int mode);
+
+int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
+             unsigned int mode);
+
+#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
new file mode 100644 (file)
index 0000000..734a6d3
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy dfa matching engine definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_MATCH_H
+#define __AA_MATCH_H
+
+#include <linux/workqueue.h>
+
+#define DFA_NOMATCH                    0
+#define DFA_START                      1
+
+#define DFA_VALID_PERM_MASK            0xffffffff
+#define DFA_VALID_PERM2_MASK           0xffffffff
+
+/**
+ * The format used for transition tables is based on the GNU flex table
+ * file format (--tables-file option; see Table File Format in the flex
+ * info pages and the flex sources for documentation). The magic number
+ * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because
+ * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
+ * slightly differently (see the apparmor-parser package).
+ */
+
+#define YYTH_MAGIC     0x1B5E783D
+#define YYTH_DEF_RECURSE 0x1                   /* DEF Table is recursive */
+
+struct table_set_header {
+       u32 th_magic;           /* YYTH_MAGIC */
+       u32 th_hsize;
+       u32 th_ssize;
+       u16 th_flags;
+       char th_version[];
+};
+
+/* The YYTD_ID are one less than flex table mappings.  The flex id
+ * has 1 subtracted at table load time, this allows us to directly use the
+ * ID's as indexes.
+ */
+#define        YYTD_ID_ACCEPT  0
+#define YYTD_ID_BASE   1
+#define YYTD_ID_CHK    2
+#define YYTD_ID_DEF    3
+#define YYTD_ID_EC     4
+#define YYTD_ID_META   5
+#define YYTD_ID_ACCEPT2 6
+#define YYTD_ID_NXT    7
+#define YYTD_ID_TSIZE  8
+
+#define YYTD_DATA8     1
+#define YYTD_DATA16    2
+#define YYTD_DATA32    4
+#define YYTD_DATA64    8
+
+/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the
+ * first flags
+ */
+#define ACCEPT1_FLAGS(X) ((X) & 0x3f)
+#define ACCEPT2_FLAGS(X) ACCEPT1_FLAGS((X) >> YYTD_ID_ACCEPT2)
+#define TO_ACCEPT1_FLAG(X) ACCEPT1_FLAGS(X)
+#define TO_ACCEPT2_FLAG(X) (ACCEPT1_FLAGS(X) << YYTD_ID_ACCEPT2)
+#define DFA_FLAG_VERIFY_STATES 0x1000
+
+struct table_header {
+       u16 td_id;
+       u16 td_flags;
+       u32 td_hilen;
+       u32 td_lolen;
+       char td_data[];
+};
+
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
+#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))
+
+struct aa_dfa {
+       struct kref count;
+       u16 flags;
+       struct table_header *tables[YYTD_ID_TSIZE];
+};
+
+#define byte_to_byte(X) (X)
+
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
+       do { \
+               typeof(LEN) __i; \
+               TYPE *__t = (TYPE *) TABLE; \
+               TYPE *__b = (TYPE *) BLOB; \
+               for (__i = 0; __i < LEN; __i++) { \
+                       __t[__i] = NTOHX(__b[__i]); \
+               } \
+       } while (0)
+
+static inline size_t table_size(size_t len, size_t el_size)
+{
+       return ALIGN(sizeof(struct table_header) + len * el_size, 8);
+}
+
+struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
+unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+                             const char *str, int len);
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+                         const char *str);
+void aa_dfa_free_kref(struct kref *kref);
+
+/**
+ * aa_put_dfa - put a dfa refcount
+ * @dfa: dfa to put refcount   (MAYBE NULL)
+ *
+ * Requires: if @dfa != NULL that a valid refcount be held
+ */
+static inline void aa_put_dfa(struct aa_dfa *dfa)
+{
+       if (dfa)
+               kref_put(&dfa->count, aa_dfa_free_kref);
+}
+
+#endif /* __AA_MATCH_H */
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
new file mode 100644 (file)
index 0000000..27b327a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic path manipulation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_PATH_H
+#define __AA_PATH_H
+
+
+enum path_flags {
+       PATH_IS_DIR = 0x1,              /* path is a directory */
+       PATH_CONNECT_PATH = 0x4,        /* connect disconnected paths to / */
+       PATH_CHROOT_REL = 0x8,          /* do path lookup relative to chroot */
+       PATH_CHROOT_NSCONNECT = 0x10,   /* connect paths that are at ns root */
+
+       PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
+       PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
+};
+
+int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
+
+#endif /* __AA_PATH_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
new file mode 100644 (file)
index 0000000..aeda5cf
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_POLICY_H
+#define __AA_POLICY_H
+
+#include <linux/capability.h>
+#include <linux/cred.h>
+#include <linux/kref.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+
+#include "apparmor.h"
+#include "audit.h"
+#include "capability.h"
+#include "domain.h"
+#include "file.h"
+#include "resource.h"
+
+extern const char *profile_mode_names[];
+#define APPARMOR_NAMES_MAX_INDEX 3
+
+#define COMPLAIN_MODE(_profile)        \
+       ((aa_g_profile_mode == APPARMOR_COMPLAIN) || \
+        ((_profile)->mode == APPARMOR_COMPLAIN))
+
+#define KILL_MODE(_profile) \
+       ((aa_g_profile_mode == APPARMOR_KILL) || \
+        ((_profile)->mode == APPARMOR_KILL))
+
+#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
+
+/*
+ * FIXME: currently need a clean way to replace and remove profiles as a
+ * set.  It should be done at the namespace level.
+ * Either, with a set of profiles loaded at the namespace level or via
+ * a mark and remove marked interface.
+ */
+enum profile_mode {
+       APPARMOR_ENFORCE,       /* enforce access rules */
+       APPARMOR_COMPLAIN,      /* allow and log access violations */
+       APPARMOR_KILL,          /* kill task on access violation */
+};
+
+enum profile_flags {
+       PFLAG_HAT = 1,                  /* profile is a hat */
+       PFLAG_UNCONFINED = 2,           /* profile is an unconfined profile */
+       PFLAG_NULL = 4,                 /* profile is null learning profile */
+       PFLAG_IX_ON_NAME_ERROR = 8,     /* fallback to ix on name lookup fail */
+       PFLAG_IMMUTABLE = 0x10,         /* don't allow changes/replacement */
+       PFLAG_USER_DEFINED = 0x20,      /* user based profile - lower privs */
+       PFLAG_NO_LIST_REF = 0x40,       /* list doesn't keep profile ref */
+       PFLAG_OLD_NULL_TRANS = 0x100,   /* use // as the null transition */
+
+       /* These flags must correspond with PATH_flags */
+       PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
+};
+
+struct aa_profile;
+
+/* struct aa_policy - common part of both namespaces and profiles
+ * @name: name of the object
+ * @hname - The hierarchical name
+ * @count: reference count of the obj
+ * @list: list policy object is on
+ * @profiles: head of the profiles list contained in the object
+ */
+struct aa_policy {
+       char *name;
+       char *hname;
+       struct kref count;
+       struct list_head list;
+       struct list_head profiles;
+};
+
+/* struct aa_ns_acct - accounting of profiles in namespace
+ * @max_size: maximum space allowed for all profiles in namespace
+ * @max_count: maximum number of profiles that can be in this namespace
+ * @size: current size of profiles
+ * @count: current count of profiles (includes null profiles)
+ */
+struct aa_ns_acct {
+       int max_size;
+       int max_count;
+       int size;
+       int count;
+};
+
+/* struct aa_namespace - namespace for a set of profiles
+ * @base: common policy
+ * @parent: parent of namespace
+ * @lock: lock for modifying the object
+ * @acct: accounting for the namespace
+ * @unconfined: special unconfined profile for the namespace
+ * @sub_ns: list of namespaces under the current namespace.
+ *
+ * An aa_namespace defines the set profiles that are searched to determine
+ * which profile to attach to a task.  Profiles can not be shared between
+ * aa_namespaces and profile names within a namespace are guaranteed to be
+ * unique.  When profiles in separate namespaces have the same name they
+ * are NOT considered to be equivalent.
+ *
+ * Namespaces are hierarchical and only namespaces and profiles below the
+ * current namespace are visible.
+ *
+ * Namespace names must be unique and can not contain the characters :/\0
+ *
+ * FIXME TODO: add vserver support of namespaces (can it all be done in
+ *             userspace?)
+ */
+struct aa_namespace {
+       struct aa_policy base;
+       struct aa_namespace *parent;
+       rwlock_t lock;
+       struct aa_ns_acct acct;
+       struct aa_profile *unconfined;
+       struct list_head sub_ns;
+};
+
+/* struct aa_profile - basic confinement data
+ * @base - base components of the profile (name, refcount, lists, lock ...)
+ * @parent: parent of profile
+ * @ns: namespace the profile is in
+ * @replacedby: is set to the profile that replaced this profile
+ * @rename: optional profile name that this profile renamed
+ * @xmatch: optional extended matching for unconfined executables names
+ * @xmatch_len: xmatch prefix len, used to determine xmatch priority
+ * @sid: the unique security id number of this profile
+ * @audit: the auditing mode of the profile
+ * @mode: the enforcement mode of the profile
+ * @flags: flags controlling profile behavior
+ * @path_flags: flags controlling path generation behavior
+ * @size: the memory consumed by this profiles rules
+ * @file: The set of rules governing basic file access and domain transitions
+ * @caps: capabilities for the profile
+ * @rlimits: rlimits for the profile
+ *
+ * The AppArmor profile contains the basic confinement data.  Each profile
+ * has a name, and exists in a namespace.  The @name and @exec_match are
+ * used to determine profile attachment against unconfined tasks.  All other
+ * attachments are determined by profile X transition rules.
+ *
+ * The @replacedby field is write protected by the profile lock.  Reads
+ * are assumed to be atomic, and are done without locking.
+ *
+ * Profiles have a hierarchy where hats and children profiles keep
+ * a reference to their parent.
+ *
+ * Profile names can not begin with a : and can not contain the \0
+ * character.  If a profile name begins with / it will be considered when
+ * determining profile attachment on "unconfined" tasks.
+ */
+struct aa_profile {
+       struct aa_policy base;
+       struct aa_profile *parent;
+
+       struct aa_namespace *ns;
+       struct aa_profile *replacedby;
+       const char *rename;
+
+       struct aa_dfa *xmatch;
+       int xmatch_len;
+       u32 sid;
+       enum audit_mode audit;
+       enum profile_mode mode;
+       u32 flags;
+       u32 path_flags;
+       int size;
+
+       struct aa_file_rules file;
+       struct aa_caps caps;
+       struct aa_rlimit rlimits;
+};
+
+extern struct aa_namespace *root_ns;
+extern enum profile_mode aa_g_profile_mode;
+
+void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
+
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
+const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
+int aa_alloc_root_ns(void);
+void aa_free_root_ns(void);
+void aa_free_namespace_kref(struct kref *kref);
+
+struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
+                                      const char *name);
+
+static inline struct aa_policy *aa_get_common(struct aa_policy *c)
+{
+       if (c)
+               kref_get(&c->count);
+
+       return c;
+}
+
+/**
+ * aa_get_namespace - increment references count on @ns
+ * @ns: namespace to increment reference count of (MAYBE NULL)
+ *
+ * Returns: pointer to @ns, if @ns is NULL returns NULL
+ * Requires: @ns must be held with valid refcount when called
+ */
+static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
+{
+       if (ns)
+               kref_get(&(ns->base.count));
+
+       return ns;
+}
+
+/**
+ * aa_put_namespace - decrement refcount on @ns
+ * @ns: namespace to put reference of
+ *
+ * Decrement reference count of @ns and if no longer in use free it
+ */
+static inline void aa_put_namespace(struct aa_namespace *ns)
+{
+       if (ns)
+               kref_put(&ns->base.count, aa_free_namespace_kref);
+}
+
+struct aa_profile *aa_alloc_profile(const char *name);
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
+void aa_free_profile_kref(struct kref *kref);
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
+struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
+struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
+
+ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
+ssize_t aa_remove_profiles(char *name, size_t size);
+
+#define PROF_ADD 1
+#define PROF_REPLACE 0
+
+#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
+
+/**
+ * aa_newest_version - find the newest version of @profile
+ * @profile: the profile to check for newer versions of (NOT NULL)
+ *
+ * Returns: newest version of @profile, if @profile is the newest version
+ *          return @profile.
+ *
+ * NOTE: the profile returned is not refcounted, The refcount on @profile
+ * must be held until the caller decides what to do with the returned newest
+ * version.
+ */
+static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
+{
+       while (profile->replacedby)
+               profile = profile->replacedby;
+
+       return profile;
+}
+
+/**
+ * aa_get_profile - increment refcount on profile @p
+ * @p: profile  (MAYBE NULL)
+ *
+ * Returns: pointer to @p if @p is NULL will return NULL
+ * Requires: @p must be held with valid refcount when called
+ */
+static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
+{
+       if (p)
+               kref_get(&(p->base.count));
+
+       return p;
+}
+
+/**
+ * aa_put_profile - decrement refcount on profile @p
+ * @p: profile  (MAYBE NULL)
+ */
+static inline void aa_put_profile(struct aa_profile *p)
+{
+       if (p)
+               kref_put(&p->base.count, aa_free_profile_kref);
+}
+
+static inline int AUDIT_MODE(struct aa_profile *profile)
+{
+       if (aa_g_audit != AUDIT_NORMAL)
+               return aa_g_audit;
+
+       return profile->audit;
+}
+
+bool aa_may_manage_policy(int op);
+
+#endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
new file mode 100644 (file)
index 0000000..a2dccca
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy loading interface function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __POLICY_INTERFACE_H
+#define __POLICY_INTERFACE_H
+
+struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns);
+
+#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
new file mode 100644 (file)
index 0000000..544aa6b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /proc/<pid>/attr/ interface function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_PROCATTR_H
+#define __AA_PROCATTR_H
+
+#define AA_DO_TEST 1
+#define AA_ONEXEC  1
+
+int aa_getprocattr(struct aa_profile *profile, char **string);
+int aa_setprocattr_changehat(char *args, size_t size, int test);
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
+int aa_setprocattr_permipc(char *fqname);
+
+#endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h
new file mode 100644 (file)
index 0000000..3c88be9
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor resource limits function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_RESOURCE_H
+#define __AA_RESOURCE_H
+
+#include <linux/resource.h>
+#include <linux/sched.h>
+
+struct aa_profile;
+
+/* struct aa_rlimit - rlimit settings for the profile
+ * @mask: which hard limits to set
+ * @limits: rlimit values that override task limits
+ *
+ * AppArmor rlimits are used to set confined task rlimits.  Only the
+ * limits specified in @mask will be controlled by apparmor.
+ */
+struct aa_rlimit {
+       unsigned int mask;
+       struct rlimit limits[RLIM_NLIMITS];
+};
+
+int aa_map_resource(int resource);
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+                     struct rlimit *new_rlim);
+
+void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
+
+static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
+{
+       /* NOP */
+}
+
+#endif /* __AA_RESOURCE_H */
diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h
new file mode 100644 (file)
index 0000000..020db35
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (sid) definitions
+ *
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __AA_SID_H
+#define __AA_SID_H
+
+#include <linux/types.h>
+
+struct aa_profile;
+
+u32 aa_alloc_sid(void);
+void aa_free_sid(u32 sid);
+
+#endif /* __AA_SID_H */
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
new file mode 100644 (file)
index 0000000..649fad8
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor ipc mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/gfp.h>
+#include <linux/ptrace.h>
+
+#include "include/audit.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+/* call back to audit ptrace fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+       audit_log_format(ab, " target=");
+       audit_log_untrustedstring(ab, sa->aad.target);
+}
+
+/**
+ * aa_audit_ptrace - do auditing for ptrace
+ * @profile: profile being enforced  (NOT NULL)
+ * @target: profile being traced (NOT NULL)
+ * @error: error condition
+ *
+ * Returns: %0 or error code
+ */
+static int aa_audit_ptrace(struct aa_profile *profile,
+                          struct aa_profile *target, int error)
+{
+       struct common_audit_data sa;
+       COMMON_AUDIT_DATA_INIT(&sa, NONE);
+       sa.aad.op = OP_PTRACE;
+       sa.aad.target = target;
+       sa.aad.error = error;
+
+       return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
+                       audit_cb);
+}
+
+/**
+ * aa_may_ptrace - test if tracer task can trace the tracee
+ * @tracer_task: task who will do the tracing  (NOT NULL)
+ * @tracer: profile of the task doing the tracing  (NOT NULL)
+ * @tracee: task to be traced
+ * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
+                 struct aa_profile *tracee, unsigned int mode)
+{
+       /* TODO: currently only based on capability, not extended ptrace
+        *       rules,
+        *       Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+        */
+
+       if (unconfined(tracer) || tracer == tracee)
+               return 0;
+       /* log this capability request */
+       return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
+}
+
+/**
+ * aa_ptrace - do ptrace permission check and auditing
+ * @tracer: task doing the tracing (NOT NULL)
+ * @tracee: task being traced (NOT NULL)
+ * @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
+             unsigned int mode)
+{
+       /*
+        * tracer can ptrace tracee when
+        * - tracer is unconfined ||
+        *   - tracer is in complain mode
+        *   - tracer has rules allowing it to trace tracee currently this is:
+        *       - confined by the same profile ||
+        *       - tracer profile has CAP_SYS_PTRACE
+        */
+
+       struct aa_profile *tracer_p;
+       /* cred released below */
+       const struct cred *cred = get_task_cred(tracer);
+       int error = 0;
+       tracer_p = aa_cred_profile(cred);
+
+       if (!unconfined(tracer_p)) {
+               /* lcred released below */
+               const struct cred *lcred = get_task_cred(tracee);
+               struct aa_profile *tracee_p = aa_cred_profile(lcred);
+
+               error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
+               error = aa_audit_ptrace(tracer_p, tracee_p, error);
+
+               put_cred(lcred);
+       }
+       put_cred(cred);
+
+       return error;
+}
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
new file mode 100644 (file)
index 0000000..6e85cdb
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains basic common functions used in AppArmor
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include "include/audit.h"
+
+
+/**
+ * aa_split_fqname - split a fqname into a profile and namespace name
+ * @fqname: a full qualified name in namespace profile format (NOT NULL)
+ * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
+ *
+ * Returns: profile name or NULL if one is not specified
+ *
+ * Split a namespace name from a profile name (see policy.c for naming
+ * description).  If a portion of the name is missing it returns NULL for
+ * that portion.
+ *
+ * NOTE: may modify the @fqname string.  The pointers returned point
+ *       into the @fqname string.
+ */
+char *aa_split_fqname(char *fqname, char **ns_name)
+{
+       char *name = strim(fqname);
+
+       *ns_name = NULL;
+       if (name[0] == ':') {
+               char *split = strchr(&name[1], ':');
+               if (split) {
+                       /* overwrite ':' with \0 */
+                       *split = 0;
+                       name = skip_spaces(split + 1);
+               } else
+                       /* a ns name without a following profile is allowed */
+                       name = NULL;
+               *ns_name = &name[1];
+       }
+       if (name && *name == 0)
+               name = NULL;
+
+       return name;
+}
+
+/**
+ * aa_info_message - log a none profile related status message
+ * @str: message to log
+ */
+void aa_info_message(const char *str)
+{
+       if (audit_enabled) {
+               struct common_audit_data sa;
+               COMMON_AUDIT_DATA_INIT(&sa, NONE);
+               sa.aad.info = str;
+               aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
+       }
+       printk(KERN_INFO "AppArmor: %s\n", str);
+}
+
+/**
+ * kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
+ * @size: size of allocation
+ *
+ * Return: allocated buffer or NULL if failed
+ *
+ * It is possible that policy being loaded from the user is larger than
+ * what can be allocated by kmalloc, in those cases fall back to vmalloc.
+ */
+void *kvmalloc(size_t size)
+{
+       void *buffer = NULL;
+
+       if (size == 0)
+               return NULL;
+
+       /* do not attempt kmalloc if we need more than 16 pages at once */
+       if (size <= (16*PAGE_SIZE))
+               buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN);
+       if (!buffer) {
+               /* see kvfree for why size must be at least work_struct size
+                * when allocated via vmalloc
+                */
+               if (size < sizeof(struct work_struct))
+                       size = sizeof(struct work_struct);
+               buffer = vmalloc(size);
+       }
+       return buffer;
+}
+
+/**
+ * do_vfree - workqueue routine for freeing vmalloced memory
+ * @work: data to be freed
+ *
+ * The work_struct is overlaid to the data being freed, as at the point
+ * the work is scheduled the data is no longer valid, be its freeing
+ * needs to be delayed until safe.
+ */
+static void do_vfree(struct work_struct *work)
+{
+       vfree(work);
+}
+
+/**
+ * kvfree - free an allocation do by kvmalloc
+ * @buffer: buffer to free (MAYBE_NULL)
+ *
+ * Free a buffer allocated by kvmalloc
+ */
+void kvfree(void *buffer)
+{
+       if (is_vmalloc_addr(buffer)) {
+               /* Data is no longer valid so just use the allocated space
+                * as the work_struct
+                */
+               struct work_struct *work = (struct work_struct *) buffer;
+               INIT_WORK(work, do_vfree);
+               schedule_work(work);
+       } else
+               kfree(buffer);
+}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
new file mode 100644 (file)
index 0000000..8db33a8
--- /dev/null
@@ -0,0 +1,938 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor LSM hooks.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/security.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/ptrace.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/audit.h>
+#include <net/sock.h>
+
+#include "include/apparmor.h"
+#include "include/apparmorfs.h"
+#include "include/audit.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/path.h"
+#include "include/policy.h"
+#include "include/procattr.h"
+
+/* Flag indicating whether initialization completed */
+int apparmor_initialized __initdata;
+
+/*
+ * LSM hook functions
+ */
+
+/*
+ * free the associated aa_task_cxt and put its profiles
+ */
+static void apparmor_cred_free(struct cred *cred)
+{
+       aa_free_task_context(cred->security);
+       cred->security = NULL;
+}
+
+/*
+ * allocate the apparmor part of blank credentials
+ */
+static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       /* freed by apparmor_cred_free */
+       struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
+       if (!cxt)
+               return -ENOMEM;
+
+       cred->security = cxt;
+       return 0;
+}
+
+/*
+ * prepare new aa_task_cxt for modification by prepare_cred block
+ */
+static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
+                                gfp_t gfp)
+{
+       /* freed by apparmor_cred_free */
+       struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
+       if (!cxt)
+               return -ENOMEM;
+
+       aa_dup_task_context(cxt, old->security);
+       new->security = cxt;
+       return 0;
+}
+
+/*
+ * transfer the apparmor data to a blank set of creds
+ */
+static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
+{
+       const struct aa_task_cxt *old_cxt = old->security;
+       struct aa_task_cxt *new_cxt = new->security;
+
+       aa_dup_task_context(new_cxt, old_cxt);
+}
+
+static int apparmor_ptrace_access_check(struct task_struct *child,
+                                       unsigned int mode)
+{
+       int error = cap_ptrace_access_check(child, mode);
+       if (error)
+               return error;
+
+       return aa_ptrace(current, child, mode);
+}
+
+static int apparmor_ptrace_traceme(struct task_struct *parent)
+{
+       int error = cap_ptrace_traceme(parent);
+       if (error)
+               return error;
+
+       return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
+}
+
+/* Derived from security/commoncap.c:cap_capget */
+static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
+                          kernel_cap_t *inheritable, kernel_cap_t *permitted)
+{
+       struct aa_profile *profile;
+       const struct cred *cred;
+
+       rcu_read_lock();
+       cred = __task_cred(target);
+       profile = aa_cred_profile(cred);
+
+       *effective = cred->cap_effective;
+       *inheritable = cred->cap_inheritable;
+       *permitted = cred->cap_permitted;
+
+       if (!unconfined(profile)) {
+               *effective = cap_intersect(*effective, profile->caps.allow);
+               *permitted = cap_intersect(*permitted, profile->caps.allow);
+       }
+       rcu_read_unlock();
+
+       return 0;
+}
+
+static int apparmor_capable(struct task_struct *task, const struct cred *cred,
+                           int cap, int audit)
+{
+       struct aa_profile *profile;
+       /* cap_capable returns 0 on success, else -EPERM */
+       int error = cap_capable(task, cred, cap, audit);
+       if (!error) {
+               profile = aa_cred_profile(cred);
+               if (!unconfined(profile))
+                       error = aa_capable(task, profile, cap, audit);
+       }
+       return error;
+}
+
+/**
+ * common_perm - basic common permission check wrapper fn for paths
+ * @op: operation being checked
+ * @path: path to check permission of  (NOT NULL)
+ * @mask: requested permissions mask
+ * @cond: conditional info for the permission request  (NOT NULL)
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm(int op, struct path *path, u32 mask,
+                      struct path_cond *cond)
+{
+       struct aa_profile *profile;
+       int error = 0;
+
+       profile = __aa_current_profile();
+       if (!unconfined(profile))
+               error = aa_path_perm(op, profile, path, 0, mask, cond);
+
+       return error;
+}
+
+/**
+ * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
+ * @op: operation being checked
+ * @dir: directory of the dentry  (NOT NULL)
+ * @dentry: dentry to check  (NOT NULL)
+ * @mask: requested permissions mask
+ * @cond: conditional info for the permission request  (NOT NULL)
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_dir_dentry(int op, struct path *dir,
+                                 struct dentry *dentry, u32 mask,
+                                 struct path_cond *cond)
+{
+       struct path path = { dir->mnt, dentry };
+
+       return common_perm(op, &path, mask, cond);
+}
+
+/**
+ * common_perm_mnt_dentry - common permission wrapper when mnt, dentry
+ * @op: operation being checked
+ * @mnt: mount point of dentry (NOT NULL)
+ * @dentry: dentry to check  (NOT NULL)
+ * @mask: requested permissions mask
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
+                                 struct dentry *dentry, u32 mask)
+{
+       struct path path = { mnt, dentry };
+       struct path_cond cond = { dentry->d_inode->i_uid,
+                                 dentry->d_inode->i_mode
+       };
+
+       return common_perm(op, &path, mask, &cond);
+}
+
+/**
+ * common_perm_rm - common permission wrapper for operations doing rm
+ * @op: operation being checked
+ * @dir: directory that the dentry is in  (NOT NULL)
+ * @dentry: dentry being rm'd  (NOT NULL)
+ * @mask: requested permission mask
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_rm(int op, struct path *dir,
+                         struct dentry *dentry, u32 mask)
+{
+       struct inode *inode = dentry->d_inode;
+       struct path_cond cond = { };
+
+       if (!inode || !dir->mnt || !mediated_filesystem(inode))
+               return 0;
+
+       cond.uid = inode->i_uid;
+       cond.mode = inode->i_mode;
+
+       return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
+}
+
+/**
+ * common_perm_create - common permission wrapper for operations doing create
+ * @op: operation being checked
+ * @dir: directory that dentry will be created in  (NOT NULL)
+ * @dentry: dentry to create   (NOT NULL)
+ * @mask: request permission mask
+ * @mode: created file mode
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_create(int op, struct path *dir, struct dentry *dentry,
+                             u32 mask, umode_t mode)
+{
+       struct path_cond cond = { current_fsuid(), mode };
+
+       if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode))
+               return 0;
+
+       return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
+}
+
+static int apparmor_path_unlink(struct path *dir, struct dentry *dentry)
+{
+       return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
+}
+
+static int apparmor_path_mkdir(struct path *dir, struct dentry *dentry,
+                              int mode)
+{
+       return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
+                                 S_IFDIR);
+}
+
+static int apparmor_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+       return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
+}
+
+static int apparmor_path_mknod(struct path *dir, struct dentry *dentry,
+                              int mode, unsigned int dev)
+{
+       return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode);
+}
+
+static int apparmor_path_truncate(struct path *path)
+{
+       struct path_cond cond = { path->dentry->d_inode->i_uid,
+                                 path->dentry->d_inode->i_mode
+       };
+
+       if (!path->mnt || !mediated_filesystem(path->dentry->d_inode))
+               return 0;
+
+       return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE,
+                          &cond);
+}
+
+static int apparmor_path_symlink(struct path *dir, struct dentry *dentry,
+                                const char *old_name)
+{
+       return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
+                                 S_IFLNK);
+}
+
+static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir,
+                             struct dentry *new_dentry)
+{
+       struct aa_profile *profile;
+       int error = 0;
+
+       if (!mediated_filesystem(old_dentry->d_inode))
+               return 0;
+
+       profile = aa_current_profile();
+       if (!unconfined(profile))
+               error = aa_path_link(profile, old_dentry, new_dir, new_dentry);
+       return error;
+}
+
+static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry,
+                               struct path *new_dir, struct dentry *new_dentry)
+{
+       struct aa_profile *profile;
+       int error = 0;
+
+       if (!mediated_filesystem(old_dentry->d_inode))
+               return 0;
+
+       profile = aa_current_profile();
+       if (!unconfined(profile)) {
+               struct path old_path = { old_dir->mnt, old_dentry };
+               struct path new_path = { new_dir->mnt, new_dentry };
+               struct path_cond cond = { old_dentry->d_inode->i_uid,
+                                         old_dentry->d_inode->i_mode
+               };
+
+               error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0,
+                                    MAY_READ | AA_MAY_META_READ | MAY_WRITE |
+                                    AA_MAY_META_WRITE | AA_MAY_DELETE,
+                                    &cond);
+               if (!error)
+                       error = aa_path_perm(OP_RENAME_DEST, profile, &new_path,
+                                            0, MAY_WRITE | AA_MAY_META_WRITE |
+                                            AA_MAY_CREATE, &cond);
+
+       }
+       return error;
+}
+
+static int apparmor_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+                              mode_t mode)
+{
+       if (!mediated_filesystem(dentry->d_inode))
+               return 0;
+
+       return common_perm_mnt_dentry(OP_CHMOD, mnt, dentry, AA_MAY_CHMOD);
+}
+
+static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+       struct path_cond cond =  { path->dentry->d_inode->i_uid,
+                                  path->dentry->d_inode->i_mode
+       };
+
+       if (!mediated_filesystem(path->dentry->d_inode))
+               return 0;
+
+       return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond);
+}
+
+static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+       if (!mediated_filesystem(dentry->d_inode))
+               return 0;
+
+       return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry,
+                                     AA_MAY_META_READ);
+}
+
+static int apparmor_dentry_open(struct file *file, const struct cred *cred)
+{
+       struct aa_file_cxt *fcxt = file->f_security;
+       struct aa_profile *profile;
+       int error = 0;
+
+       if (!mediated_filesystem(file->f_path.dentry->d_inode))
+               return 0;
+
+       /* If in exec, permission is handled by bprm hooks.
+        * Cache permissions granted by the previous exec check, with
+        * implicit read and executable mmap which are required to
+        * actually execute the image.
+        */
+       if (current->in_execve) {
+               fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
+               return 0;
+       }
+
+       profile = aa_cred_profile(cred);
+       if (!unconfined(profile)) {
+               struct inode *inode = file->f_path.dentry->d_inode;
+               struct path_cond cond = { inode->i_uid, inode->i_mode };
+
+               error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0,
+                                    aa_map_file_to_perms(file), &cond);
+               /* todo cache full allowed permissions set and state */
+               fcxt->allow = aa_map_file_to_perms(file);
+       }
+
+       return error;
+}
+
+static int apparmor_file_alloc_security(struct file *file)
+{
+       /* freed by apparmor_file_free_security */
+       file->f_security = aa_alloc_file_context(GFP_KERNEL);
+       if (!file->f_security)
+               return -ENOMEM;
+       return 0;
+
+}
+
+static void apparmor_file_free_security(struct file *file)
+{
+       struct aa_file_cxt *cxt = file->f_security;
+
+       aa_free_file_context(cxt);
+}
+
+static int common_file_perm(int op, struct file *file, u32 mask)
+{
+       struct aa_file_cxt *fcxt = file->f_security;
+       struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
+       int error = 0;
+
+       BUG_ON(!fprofile);
+
+       if (!file->f_path.mnt ||
+           !mediated_filesystem(file->f_path.dentry->d_inode))
+               return 0;
+
+       profile = __aa_current_profile();
+
+       /* revalidate access, if task is unconfined, or the cached cred
+        * doesn't match or if the request is for more permissions than
+        * was granted.
+        *
+        * Note: the test for !unconfined(fprofile) is to handle file
+        *       delegation from unconfined tasks
+        */
+       if (!unconfined(profile) && !unconfined(fprofile) &&
+           ((fprofile != profile) || (mask & ~fcxt->allow)))
+               error = aa_file_perm(op, profile, file, mask);
+
+       return error;
+}
+
+static int apparmor_file_permission(struct file *file, int mask)
+{
+       return common_file_perm(OP_FPERM, file, mask);
+}
+
+static int apparmor_file_lock(struct file *file, unsigned int cmd)
+{
+       u32 mask = AA_MAY_LOCK;
+
+       if (cmd == F_WRLCK)
+               mask |= MAY_WRITE;
+
+       return common_file_perm(OP_FLOCK, file, mask);
+}
+
+static int common_mmap(int op, struct file *file, unsigned long prot,
+                      unsigned long flags)
+{
+       struct dentry *dentry;
+       int mask = 0;
+
+       if (!file || !file->f_security)
+               return 0;
+
+       if (prot & PROT_READ)
+               mask |= MAY_READ;
+       /*
+        * Private mappings don't require write perms since they don't
+        * write back to the files
+        */
+       if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+               mask |= MAY_WRITE;
+       if (prot & PROT_EXEC)
+               mask |= AA_EXEC_MMAP;
+
+       dentry = file->f_path.dentry;
+       return common_file_perm(op, file, mask);
+}
+
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
+                             unsigned long prot, unsigned long flags,
+                             unsigned long addr, unsigned long addr_only)
+{
+       int rc = 0;
+
+       /* do DAC check */
+       rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
+       if (rc || addr_only)
+               return rc;
+
+       return common_mmap(OP_FMMAP, file, prot, flags);
+}
+
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
+                                 unsigned long reqprot, unsigned long prot)
+{
+       return common_mmap(OP_FMPROT, vma->vm_file, prot,
+                          !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+}
+
+static int apparmor_getprocattr(struct task_struct *task, char *name,
+                               char **value)
+{
+       int error = -ENOENT;
+       struct aa_profile *profile;
+       /* released below */
+       const struct cred *cred = get_task_cred(task);
+       struct aa_task_cxt *cxt = cred->security;
+       profile = aa_cred_profile(cred);
+
+       if (strcmp(name, "current") == 0)
+               error = aa_getprocattr(aa_newest_version(cxt->profile),
+                                      value);
+       else if (strcmp(name, "prev") == 0  && cxt->previous)
+               error = aa_getprocattr(aa_newest_version(cxt->previous),
+                                      value);
+       else if (strcmp(name, "exec") == 0 && cxt->onexec)
+               error = aa_getprocattr(aa_newest_version(cxt->onexec),
+                                      value);
+       else
+               error = -EINVAL;
+
+       put_cred(cred);
+
+       return error;
+}
+
+static int apparmor_setprocattr(struct task_struct *task, char *name,
+                               void *value, size_t size)
+{
+       char *command, *args = value;
+       size_t arg_size;
+       int error;
+
+       if (size == 0)
+               return -EINVAL;
+       /* args points to a PAGE_SIZE buffer, AppArmor requires that
+        * the buffer must be null terminated or have size <= PAGE_SIZE -1
+        * so that AppArmor can null terminate them
+        */
+       if (args[size - 1] != '\0') {
+               if (size == PAGE_SIZE)
+                       return -EINVAL;
+               args[size] = '\0';
+       }
+
+       /* task can only write its own attributes */
+       if (current != task)
+               return -EACCES;
+
+       args = value;
+       args = strim(args);
+       command = strsep(&args, " ");
+       if (!args)
+               return -EINVAL;
+       args = skip_spaces(args);
+       if (!*args)
+               return -EINVAL;
+
+       arg_size = size - (args - (char *) value);
+       if (strcmp(name, "current") == 0) {
+               if (strcmp(command, "changehat") == 0) {
+                       error = aa_setprocattr_changehat(args, arg_size,
+                                                        !AA_DO_TEST);
+               } else if (strcmp(command, "permhat") == 0) {
+                       error = aa_setprocattr_changehat(args, arg_size,
+                                                        AA_DO_TEST);
+               } else if (strcmp(command, "changeprofile") == 0) {
+                       error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
+                                                            !AA_DO_TEST);
+               } else if (strcmp(command, "permprofile") == 0) {
+                       error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
+                                                            AA_DO_TEST);
+               } else if (strcmp(command, "permipc") == 0) {
+                       error = aa_setprocattr_permipc(args);
+               } else {
+                       struct common_audit_data sa;
+                       COMMON_AUDIT_DATA_INIT(&sa, NONE);
+                       sa.aad.op = OP_SETPROCATTR;
+                       sa.aad.info = name;
+                       sa.aad.error = -EINVAL;
+                       return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL,
+                                       &sa, NULL);
+               }
+       } else if (strcmp(name, "exec") == 0) {
+               error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
+                                                    !AA_DO_TEST);
+       } else {
+               /* only support the "current" and "exec" process attributes */
+               return -EINVAL;
+       }
+       if (!error)
+               error = size;
+       return error;
+}
+
+static int apparmor_task_setrlimit(unsigned int resource,
+                                  struct rlimit *new_rlim)
+{
+       struct aa_profile *profile = aa_current_profile();
+       int error = 0;
+
+       if (!unconfined(profile))
+               error = aa_task_setrlimit(profile, resource, new_rlim);
+
+       return error;
+}
+
+static struct security_operations apparmor_ops = {
+       .name =                         "apparmor",
+
+       .ptrace_access_check =          apparmor_ptrace_access_check,
+       .ptrace_traceme =               apparmor_ptrace_traceme,
+       .capget =                       apparmor_capget,
+       .capable =                      apparmor_capable,
+
+       .path_link =                    apparmor_path_link,
+       .path_unlink =                  apparmor_path_unlink,
+       .path_symlink =                 apparmor_path_symlink,
+       .path_mkdir =                   apparmor_path_mkdir,
+       .path_rmdir =                   apparmor_path_rmdir,
+       .path_mknod =                   apparmor_path_mknod,
+       .path_rename =                  apparmor_path_rename,
+       .path_chmod =                   apparmor_path_chmod,
+       .path_chown =                   apparmor_path_chown,
+       .path_truncate =                apparmor_path_truncate,
+       .dentry_open =                  apparmor_dentry_open,
+       .inode_getattr =                apparmor_inode_getattr,
+
+       .file_permission =              apparmor_file_permission,
+       .file_alloc_security =          apparmor_file_alloc_security,
+       .file_free_security =           apparmor_file_free_security,
+       .file_mmap =                    apparmor_file_mmap,
+       .file_mprotect =                apparmor_file_mprotect,
+       .file_lock =                    apparmor_file_lock,
+
+       .getprocattr =                  apparmor_getprocattr,
+       .setprocattr =                  apparmor_setprocattr,
+
+       .cred_alloc_blank =             apparmor_cred_alloc_blank,
+       .cred_free =                    apparmor_cred_free,
+       .cred_prepare =                 apparmor_cred_prepare,
+       .cred_transfer =                apparmor_cred_transfer,
+
+       .bprm_set_creds =               apparmor_bprm_set_creds,
+       .bprm_committing_creds =        apparmor_bprm_committing_creds,
+       .bprm_committed_creds =         apparmor_bprm_committed_creds,
+       .bprm_secureexec =              apparmor_bprm_secureexec,
+
+       .task_setrlimit =               apparmor_task_setrlimit,
+};
+
+/*
+ * AppArmor sysfs module parameters
+ */
+
+static int param_set_aabool(const char *val, struct kernel_param *kp);
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
+#define param_check_aabool(name, p) __param_check(name, p, int)
+
+static int param_set_aauint(const char *val, struct kernel_param *kp);
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
+#define param_check_aauint(name, p) __param_check(name, p, int)
+
+static int param_set_aalockpolicy(const char *val, struct kernel_param *kp);
+static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp);
+#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
+
+static int param_set_audit(const char *val, struct kernel_param *kp);
+static int param_get_audit(char *buffer, struct kernel_param *kp);
+#define param_check_audit(name, p) __param_check(name, p, int)
+
+static int param_set_mode(const char *val, struct kernel_param *kp);
+static int param_get_mode(char *buffer, struct kernel_param *kp);
+#define param_check_mode(name, p) __param_check(name, p, int)
+
+/* Flag values, also controllable via /sys/module/apparmor/parameters
+ * We define special types as we want to do additional mediation.
+ */
+
+/* AppArmor global enforcement switch - complain, enforce, kill */
+enum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE;
+module_param_call(mode, param_set_mode, param_get_mode,
+                 &aa_g_profile_mode, S_IRUSR | S_IWUSR);
+
+/* Debug mode */
+int aa_g_debug;
+module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
+
+/* Audit mode */
+enum audit_mode aa_g_audit;
+module_param_call(audit, param_set_audit, param_get_audit,
+                 &aa_g_audit, S_IRUSR | S_IWUSR);
+
+/* Determines if audit header is included in audited messages.  This
+ * provides more context if the audit daemon is not running
+ */
+int aa_g_audit_header = 1;
+module_param_named(audit_header, aa_g_audit_header, aabool,
+                  S_IRUSR | S_IWUSR);
+
+/* lock out loading/removal of policy
+ * TODO: add in at boot loading of policy, which is the only way to
+ *       load policy, if lock_policy is set
+ */
+int aa_g_lock_policy;
+module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
+                  S_IRUSR | S_IWUSR);
+
+/* Syscall logging mode */
+int aa_g_logsyscall;
+module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
+
+/* Maximum pathname length before accesses will start getting rejected */
+unsigned int aa_g_path_max = 2 * PATH_MAX;
+module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
+
+/* Determines how paranoid loading of policy is and how much verification
+ * on the loaded policy is done.
+ */
+int aa_g_paranoid_load = 1;
+module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
+                  S_IRUSR | S_IWUSR);
+
+/* Boot time disable flag */
+static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR);
+
+static int __init apparmor_enabled_setup(char *str)
+{
+       unsigned long enabled;
+       int error = strict_strtoul(str, 0, &enabled);
+       if (!error)
+               apparmor_enabled = enabled ? 1 : 0;
+       return 1;
+}
+
+__setup("apparmor=", apparmor_enabled_setup);
+
+/* set global flag turning off the ability to load policy */
+static int param_set_aalockpolicy(const char *val, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       if (aa_g_lock_policy)
+               return -EACCES;
+       return param_set_bool(val, kp);
+}
+
+static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       return param_get_bool(buffer, kp);
+}
+
+static int param_set_aabool(const char *val, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       return param_set_bool(val, kp);
+}
+
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       return param_get_bool(buffer, kp);
+}
+
+static int param_set_aauint(const char *val, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       return param_set_uint(val, kp);
+}
+
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       return param_get_uint(buffer, kp);
+}
+
+static int param_get_audit(char *buffer, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (!apparmor_enabled)
+               return -EINVAL;
+
+       return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
+}
+
+static int param_set_audit(const char *val, struct kernel_param *kp)
+{
+       int i;
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (!apparmor_enabled)
+               return -EINVAL;
+
+       if (!val)
+               return -EINVAL;
+
+       for (i = 0; i < AUDIT_MAX_INDEX; i++) {
+               if (strcmp(val, audit_mode_names[i]) == 0) {
+                       aa_g_audit = i;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int param_get_mode(char *buffer, struct kernel_param *kp)
+{
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (!apparmor_enabled)
+               return -EINVAL;
+
+       return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]);
+}
+
+static int param_set_mode(const char *val, struct kernel_param *kp)
+{
+       int i;
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (!apparmor_enabled)
+               return -EINVAL;
+
+       if (!val)
+               return -EINVAL;
+
+       for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) {
+               if (strcmp(val, profile_mode_names[i]) == 0) {
+                       aa_g_profile_mode = i;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * AppArmor init functions
+ */
+
+/**
+ * set_init_cxt - set a task context and profile on the first task.
+ *
+ * TODO: allow setting an alternate profile than unconfined
+ */
+static int __init set_init_cxt(void)
+{
+       struct cred *cred = (struct cred *)current->real_cred;
+       struct aa_task_cxt *cxt;
+
+       cxt = aa_alloc_task_context(GFP_KERNEL);
+       if (!cxt)
+               return -ENOMEM;
+
+       cxt->profile = aa_get_profile(root_ns->unconfined);
+       cred->security = cxt;
+
+       return 0;
+}
+
+static int __init apparmor_init(void)
+{
+       int error;
+
+       if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
+               aa_info_message("AppArmor disabled by boot time parameter");
+               apparmor_enabled = 0;
+               return 0;
+       }
+
+       error = aa_alloc_root_ns();
+       if (error) {
+               AA_ERROR("Unable to allocate default profile namespace\n");
+               goto alloc_out;
+       }
+
+       error = set_init_cxt();
+       if (error) {
+               AA_ERROR("Failed to set context on init task\n");
+               goto register_security_out;
+       }
+
+       error = register_security(&apparmor_ops);
+       if (error) {
+               AA_ERROR("Unable to register AppArmor\n");
+               goto register_security_out;
+       }
+
+       /* Report that AppArmor successfully initialized */
+       apparmor_initialized = 1;
+       if (aa_g_profile_mode == APPARMOR_COMPLAIN)
+               aa_info_message("AppArmor initialized: complain mode enabled");
+       else if (aa_g_profile_mode == APPARMOR_KILL)
+               aa_info_message("AppArmor initialized: kill mode enabled");
+       else
+               aa_info_message("AppArmor initialized");
+
+       return error;
+
+register_security_out:
+       aa_free_root_ns();
+
+alloc_out:
+       aa_destroy_aafs();
+
+       apparmor_enabled = 0;
+       return error;
+
+}
+
+security_initcall(apparmor_init);
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
new file mode 100644 (file)
index 0000000..5cb4dc1
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor dfa based regular expression matching engine
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/kref.h>
+
+#include "include/apparmor.h"
+#include "include/match.h"
+
+/**
+ * unpack_table - unpack a dfa table (one of accept, default, base, next check)
+ * @blob: data to unpack (NOT NULL)
+ * @bsize: size of blob
+ *
+ * Returns: pointer to table else NULL on failure
+ *
+ * NOTE: must be freed by kvfree (not kmalloc)
+ */
+static struct table_header *unpack_table(char *blob, size_t bsize)
+{
+       struct table_header *table = NULL;
+       struct table_header th;
+       size_t tsize;
+
+       if (bsize < sizeof(struct table_header))
+               goto out;
+
+       /* loaded td_id's start at 1, subtract 1 now to avoid doing
+        * it every time we use td_id as an index
+        */
+       th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
+       th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
+       th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
+       blob += sizeof(struct table_header);
+
+       if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
+             th.td_flags == YYTD_DATA8))
+               goto out;
+
+       tsize = table_size(th.td_lolen, th.td_flags);
+       if (bsize < tsize)
+               goto out;
+
+       table = kvmalloc(tsize);
+       if (table) {
+               *table = th;
+               if (th.td_flags == YYTD_DATA8)
+                       UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+                                    u8, byte_to_byte);
+               else if (th.td_flags == YYTD_DATA16)
+                       UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+                                    u16, be16_to_cpu);
+               else if (th.td_flags == YYTD_DATA32)
+                       UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+                                    u32, be32_to_cpu);
+               else
+                       goto fail;
+       }
+
+out:
+       /* if table was vmalloced make sure the page tables are synced
+        * before it is used, as it goes live to all cpus.
+        */
+       if (is_vmalloc_addr(table))
+               vm_unmap_aliases();
+       return table;
+fail:
+       kvfree(table);
+       return NULL;
+}
+
+/**
+ * verify_dfa - verify that transitions and states in the tables are in bounds.
+ * @dfa: dfa to test  (NOT NULL)
+ * @flags: flags controlling what type of accept table are acceptable
+ *
+ * Assumes dfa has gone through the first pass verification done by unpacking
+ * NOTE: this does not valid accept table values
+ *
+ * Returns: %0 else error code on failure to verify
+ */
+static int verify_dfa(struct aa_dfa *dfa, int flags)
+{
+       size_t i, state_count, trans_count;
+       int error = -EPROTO;
+
+       /* check that required tables exist */
+       if (!(dfa->tables[YYTD_ID_DEF] &&
+             dfa->tables[YYTD_ID_BASE] &&
+             dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
+               goto out;
+
+       /* accept.size == default.size == base.size */
+       state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+       if (ACCEPT1_FLAGS(flags)) {
+               if (!dfa->tables[YYTD_ID_ACCEPT])
+                       goto out;
+               if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
+                       goto out;
+       }
+       if (ACCEPT2_FLAGS(flags)) {
+               if (!dfa->tables[YYTD_ID_ACCEPT2])
+                       goto out;
+               if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
+                       goto out;
+       }
+       if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
+               goto out;
+
+       /* next.size == chk.size */
+       trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
+       if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
+               goto out;
+
+       /* if equivalence classes then its table size must be 256 */
+       if (dfa->tables[YYTD_ID_EC] &&
+           dfa->tables[YYTD_ID_EC]->td_lolen != 256)
+               goto out;
+
+       if (flags & DFA_FLAG_VERIFY_STATES) {
+               for (i = 0; i < state_count; i++) {
+                       if (DEFAULT_TABLE(dfa)[i] >= state_count)
+                               goto out;
+                       /* TODO: do check that DEF state recursion terminates */
+                       if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
+                               printk(KERN_ERR "AppArmor DFA next/check upper "
+                                      "bounds error\n");
+                               goto out;
+                       }
+               }
+
+               for (i = 0; i < trans_count; i++) {
+                       if (NEXT_TABLE(dfa)[i] >= state_count)
+                               goto out;
+                       if (CHECK_TABLE(dfa)[i] >= state_count)
+                               goto out;
+               }
+       }
+
+       error = 0;
+out:
+       return error;
+}
+
+/**
+ * dfa_free - free a dfa allocated by aa_dfa_unpack
+ * @dfa: the dfa to free  (MAYBE NULL)
+ *
+ * Requires: reference count to dfa == 0
+ */
+static void dfa_free(struct aa_dfa *dfa)
+{
+       if (dfa) {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
+                       kvfree(dfa->tables[i]);
+                       dfa->tables[i] = NULL;
+               }
+               kfree(dfa);
+       }
+}
+
+/**
+ * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa)
+ * @kr: kref callback for freeing of a dfa  (NOT NULL)
+ */
+void aa_dfa_free_kref(struct kref *kref)
+{
+       struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count);
+       dfa_free(dfa);
+}
+
+/**
+ * aa_dfa_unpack - unpack the binary tables of a serialized dfa
+ * @blob: aligned serialized stream of data to unpack  (NOT NULL)
+ * @size: size of data to unpack
+ * @flags: flags controlling what type of accept tables are acceptable
+ *
+ * Unpack a dfa that has been serialized.  To find information on the dfa
+ * format look in Documentation/apparmor.txt
+ * Assumes the dfa @blob stream has been aligned on a 8 byte boundry
+ *
+ * Returns: an unpacked dfa ready for matching or ERR_PTR on failure
+ */
+struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
+{
+       int hsize;
+       int error = -ENOMEM;
+       char *data = blob;
+       struct table_header *table = NULL;
+       struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
+       if (!dfa)
+               goto fail;
+
+       kref_init(&dfa->count);
+
+       error = -EPROTO;
+
+       /* get dfa table set header */
+       if (size < sizeof(struct table_set_header))
+               goto fail;
+
+       if (ntohl(*(u32 *) data) != YYTH_MAGIC)
+               goto fail;
+
+       hsize = ntohl(*(u32 *) (data + 4));
+       if (size < hsize)
+               goto fail;
+
+       dfa->flags = ntohs(*(u16 *) (data + 12));
+       data += hsize;
+       size -= hsize;
+
+       while (size > 0) {
+               table = unpack_table(data, size);
+               if (!table)
+                       goto fail;
+
+               switch (table->td_id) {
+               case YYTD_ID_ACCEPT:
+                       if (!(table->td_flags & ACCEPT1_FLAGS(flags)))
+                               goto fail;
+                       break;
+               case YYTD_ID_ACCEPT2:
+                       if (!(table->td_flags & ACCEPT2_FLAGS(flags)))
+                               goto fail;
+                       break;
+               case YYTD_ID_BASE:
+                       if (table->td_flags != YYTD_DATA32)
+                               goto fail;
+                       break;
+               case YYTD_ID_DEF:
+               case YYTD_ID_NXT:
+               case YYTD_ID_CHK:
+                       if (table->td_flags != YYTD_DATA16)
+                               goto fail;
+                       break;
+               case YYTD_ID_EC:
+                       if (table->td_flags != YYTD_DATA8)
+                               goto fail;
+                       break;
+               default:
+                       goto fail;
+               }
+               /* check for duplicate table entry */
+               if (dfa->tables[table->td_id])
+                       goto fail;
+               dfa->tables[table->td_id] = table;
+               data += table_size(table->td_lolen, table->td_flags);
+               size -= table_size(table->td_lolen, table->td_flags);
+               table = NULL;
+       }
+
+       error = verify_dfa(dfa, flags);
+       if (error)
+               goto fail;
+
+       return dfa;
+
+fail:
+       kvfree(table);
+       dfa_free(dfa);
+       return ERR_PTR(error);
+}
+
+/**
+ * aa_dfa_match_len - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the string of bytes to match against the dfa  (NOT NULL)
+ * @len: length of the string of bytes to match
+ *
+ * aa_dfa_match_len will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * This function will happily match again the 0 byte and only finishes
+ * when @len input is consumed.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+                             const char *str, int len)
+{
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+       unsigned int state = start, pos;
+
+       if (state == 0)
+               return 0;
+
+       /* current state is <state>, matching character *str */
+       if (dfa->tables[YYTD_ID_EC]) {
+               /* Equivalence class table defined */
+               u8 *equiv = EQUIV_TABLE(dfa);
+               /* default is direct to next state */
+               for (; len; len--) {
+                       pos = base[state] + equiv[(u8) *str++];
+                       if (check[pos] == state)
+                               state = next[pos];
+                       else
+                               state = def[state];
+               }
+       } else {
+               /* default is direct to next state */
+               for (; len; len--) {
+                       pos = base[state] + (u8) *str++;
+                       if (check[pos] == state)
+                               state = next[pos];
+                       else
+                               state = def[state];
+               }
+       }
+
+       return state;
+}
+
+/**
+ * aa_dfa_next_state - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ *
+ * aa_dfa_next_state will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+                         const char *str)
+{
+       return aa_dfa_match_len(dfa, start, str, strlen(str));
+}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
new file mode 100644 (file)
index 0000000..96bab94
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor function for pathnames
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/magic.h>
+#include <linux/mnt_namespace.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nsproxy.h>
+#include <linux/path.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs_struct.h>
+
+#include "include/apparmor.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+/* modified from dcache.c */
+static int prepend(char **buffer, int buflen, const char *str, int namelen)
+{
+       buflen -= namelen;
+       if (buflen < 0)
+               return -ENAMETOOLONG;
+       *buffer -= namelen;
+       memcpy(*buffer, str, namelen);
+       return 0;
+}
+
+#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
+
+/**
+ * d_namespace_path - lookup a name associated with a given path
+ * @path: path to lookup  (NOT NULL)
+ * @buf:  buffer to store path to  (NOT NULL)
+ * @buflen: length of @buf
+ * @name: Returns - pointer for start of path name with in @buf (NOT NULL)
+ * @flags: flags controlling path lookup
+ *
+ * Handle path name lookup.
+ *
+ * Returns: %0 else error code if path lookup fails
+ *          When no error the path name is returned in @name which points to
+ *          to a position in @buf
+ */
+static int d_namespace_path(struct path *path, char *buf, int buflen,
+                           char **name, int flags)
+{
+       struct path root, tmp;
+       char *res;
+       int deleted, connected;
+       int error = 0;
+
+       /* Get the root we want to resolve too */
+       if (flags & PATH_CHROOT_REL) {
+               /* resolve paths relative to chroot */
+               read_lock(&current->fs->lock);
+               root = current->fs->root;
+               /* released below */
+               path_get(&root);
+               read_unlock(&current->fs->lock);
+       } else {
+               /* resolve paths relative to namespace */
+               root.mnt = current->nsproxy->mnt_ns->root;
+               root.dentry = root.mnt->mnt_root;
+               /* released below */
+               path_get(&root);
+       }
+
+       spin_lock(&dcache_lock);
+       /* There is a race window between path lookup here and the
+        * need to strip the " (deleted) string that __d_path applies
+        * Detect the race and relookup the path
+        *
+        * The stripping of (deleted) is a hack that could be removed
+        * with an updated __d_path
+        */
+       do {
+               tmp = root;
+               deleted = d_unlinked(path->dentry);
+               res = __d_path(path, &tmp, buf, buflen);
+
+       } while (deleted != d_unlinked(path->dentry));
+       spin_unlock(&dcache_lock);
+
+       *name = res;
+       /* handle error conditions - and still allow a partial path to
+        * be returned.
+        */
+       if (IS_ERR(res)) {
+               error = PTR_ERR(res);
+               *name = buf;
+               goto out;
+       }
+       if (deleted) {
+               /* On some filesystems, newly allocated dentries appear to the
+                * security_path hooks as a deleted dentry except without an
+                * inode allocated.
+                *
+                * Remove the appended deleted text and return as string for
+                * normal mediation, or auditing.  The (deleted) string is
+                * guaranteed to be added in this case, so just strip it.
+                */
+               buf[buflen - 11] = 0;   /* - (len(" (deleted)") +\0) */
+
+               if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) {
+                       error = -ENOENT;
+                       goto out;
+               }
+       }
+
+       /* Determine if the path is connected to the expected root */
+       connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
+
+       /* If the path is not connected,
+        * check if it is a sysctl and handle specially else remove any
+        * leading / that __d_path may have returned.
+        * Unless
+        *     specifically directed to connect the path,
+        * OR
+        *     if in a chroot and doing chroot relative paths and the path
+        *     resolves to the namespace root (would be connected outside
+        *     of chroot) and specifically directed to connect paths to
+        *     namespace root.
+        */
+       if (!connected) {
+               /* is the disconnect path a sysctl? */
+               if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
+                   strncmp(*name, "/sys/", 5) == 0) {
+                       /* TODO: convert over to using a per namespace
+                        * control instead of hard coded /proc
+                        */
+                       error = prepend(name, *name - buf, "/proc", 5);
+               } else if (!(flags & PATH_CONNECT_PATH) &&
+                          !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
+                            (tmp.mnt == current->nsproxy->mnt_ns->root &&
+                             tmp.dentry == tmp.mnt->mnt_root))) {
+                       /* disconnected path, don't return pathname starting
+                        * with '/'
+                        */
+                       error = -ESTALE;
+                       if (*res == '/')
+                               *name = res + 1;
+               }
+       }
+
+out:
+       path_put(&root);
+
+       return error;
+}
+
+/**
+ * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended
+ * @path: path to get name for  (NOT NULL)
+ * @flags: flags controlling path lookup
+ * @buffer: buffer to put name in  (NOT NULL)
+ * @size: size of buffer
+ * @name: Returns - contains position of path name in @buffer (NOT NULL)
+ *
+ * Returns: %0 else error on failure
+ */
+static int get_name_to_buffer(struct path *path, int flags, char *buffer,
+                             int size, char **name)
+{
+       int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
+       int error = d_namespace_path(path, buffer, size - adjust, name, flags);
+
+       if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')
+               /*
+                * Append "/" to the pathname.  The root directory is a special
+                * case; it already ends in slash.
+                */
+               strcpy(&buffer[size - 2], "/");
+
+       return error;
+}
+
+/**
+ * aa_get_name - compute the pathname of a file
+ * @path: path the file  (NOT NULL)
+ * @flags: flags controlling path name generation
+ * @buffer: buffer that aa_get_name() allocated  (NOT NULL)
+ * @name: Returns - the generated path name if !error (NOT NULL)
+ *
+ * @name is a pointer to the beginning of the pathname (which usually differs
+ * from the beginning of the buffer), or NULL.  If there is an error @name
+ * may contain a partial or invalid name that can be used for audit purposes,
+ * but it can not be used for mediation.
+ *
+ * We need PATH_IS_DIR to indicate whether the file is a directory or not
+ * because the file may not yet exist, and so we cannot check the inode's
+ * file type.
+ *
+ * Returns: %0 else error code if could retrieve name
+ */
+int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
+{
+       char *buf, *str = NULL;
+       int size = 256;
+       int error;
+
+       *name = NULL;
+       *buffer = NULL;
+       for (;;) {
+               /* freed by caller */
+               buf = kmalloc(size, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+
+               error = get_name_to_buffer(path, flags, buf, size, &str);
+               if (error != -ENAMETOOLONG)
+                       break;
+
+               kfree(buf);
+               size <<= 1;
+               if (size > aa_g_path_max)
+                       return -ENAMETOOLONG;
+       }
+       *buffer = buf;
+       *name = str;
+
+       return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
new file mode 100644 (file)
index 0000000..3cdc1ad
--- /dev/null
@@ -0,0 +1,1184 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy manipulation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ *
+ *
+ * AppArmor policy is based around profiles, which contain the rules a
+ * task is confined by.  Every task in the system has a profile attached
+ * to it determined either by matching "unconfined" tasks against the
+ * visible set of profiles or by following a profiles attachment rules.
+ *
+ * Each profile exists in a profile namespace which is a container of
+ * visible profiles.  Each namespace contains a special "unconfined" profile,
+ * which doesn't enforce any confinement on a task beyond DAC.
+ *
+ * Namespace and profile names can be written together in either
+ * of two syntaxes.
+ *     :namespace:profile - used by kernel interfaces for easy detection
+ *     namespace://profile - used by policy
+ *
+ * Profile names can not start with : or @ or ^ and may not contain \0
+ *
+ * Reserved profile names
+ *     unconfined - special automatically generated unconfined profile
+ *     inherit - special name to indicate profile inheritance
+ *     null-XXXX-YYYY - special automatically generated learning profiles
+ *
+ * Namespace names may not start with / or @ and may not contain \0 or :
+ * Reserved namespace names
+ *     user-XXXX - user defined profiles
+ *
+ * a // in a profile or namespace name indicates a hierarchical name with the
+ * name before the // being the parent and the name after the child.
+ *
+ * Profile and namespace hierarchies serve two different but similar purposes.
+ * The namespace contains the set of visible profiles that are considered
+ * for attachment.  The hierarchy of namespaces allows for virtualizing
+ * the namespace so that for example a chroot can have its own set of profiles
+ * which may define some local user namespaces.
+ * The profile hierarchy severs two distinct purposes,
+ * -  it allows for sub profiles or hats, which allows an application to run
+ *    subprograms under its own profile with different restriction than it
+ *    self, and not have it use the system profile.
+ *    eg. if a mail program starts an editor, the policy might make the
+ *        restrictions tighter on the editor tighter than the mail program,
+ *        and definitely different than general editor restrictions
+ * - it allows for binary hierarchy of profiles, so that execution history
+ *   is preserved.  This feature isn't exploited by AppArmor reference policy
+ *   but is allowed.  NOTE: this is currently suboptimal because profile
+ *   aliasing is not currently implemented so that a profile for each
+ *   level must be defined.
+ *   eg. /bin/bash///bin/ls as a name would indicate /bin/ls was started
+ *       from /bin/bash
+ *
+ *   A profile or namespace name that can contain one or more // separators
+ *   is referred to as an hname (hierarchical).
+ *   eg.  /bin/bash//bin/ls
+ *
+ *   An fqname is a name that may contain both namespace and profile hnames.
+ *   eg. :ns:/bin/bash//bin/ls
+ *
+ * NOTES:
+ *   - locking of profile lists is currently fairly coarse.  All profile
+ *     lists within a namespace use the namespace lock.
+ * FIXME: move profile lists to using rcu_lists
+ */
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include "include/apparmor.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+#include "include/policy_unpack.h"
+#include "include/resource.h"
+#include "include/sid.h"
+
+
+/* root profile namespace */
+struct aa_namespace *root_ns;
+
+const char *profile_mode_names[] = {
+       "enforce",
+       "complain",
+       "kill",
+};
+
+/**
+ * hname_tail - find the last component of an hname
+ * @name: hname to find the base profile name component of  (NOT NULL)
+ *
+ * Returns: the tail (base profile name) name component of an hname
+ */
+static const char *hname_tail(const char *hname)
+{
+       char *split;
+       hname = strim((char *)hname);
+       for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
+               hname = split + 2;
+
+       return hname;
+}
+
+/**
+ * policy_init - initialize a policy structure
+ * @policy: policy to initialize  (NOT NULL)
+ * @prefix: prefix name if any is required.  (MAYBE NULL)
+ * @name: name of the policy, init will make a copy of it  (NOT NULL)
+ *
+ * Note: this fn creates a copy of strings passed in
+ *
+ * Returns: true if policy init successful
+ */
+static bool policy_init(struct aa_policy *policy, const char *prefix,
+                       const char *name)
+{
+       /* freed by policy_free */
+       if (prefix) {
+               policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
+                                       GFP_KERNEL);
+               if (policy->hname)
+                       sprintf(policy->hname, "%s//%s", prefix, name);
+       } else
+               policy->hname = kstrdup(name, GFP_KERNEL);
+       if (!policy->hname)
+               return 0;
+       /* base.name is a substring of fqname */
+       policy->name = (char *)hname_tail(policy->hname);
+       INIT_LIST_HEAD(&policy->list);
+       INIT_LIST_HEAD(&policy->profiles);
+       kref_init(&policy->count);
+
+       return 1;
+}
+
+/**
+ * policy_destroy - free the elements referenced by @policy
+ * @policy: policy that is to have its elements freed  (NOT NULL)
+ */
+static void policy_destroy(struct aa_policy *policy)
+{
+       /* still contains profiles -- invalid */
+       if (!list_empty(&policy->profiles)) {
+               AA_ERROR("%s: internal error, "
+                        "policy '%s' still contains profiles\n",
+                        __func__, policy->name);
+               BUG();
+       }
+       if (!list_empty(&policy->list)) {
+               AA_ERROR("%s: internal error, policy '%s' still on list\n",
+                        __func__, policy->name);
+               BUG();
+       }
+
+       /* don't free name as its a subset of hname */
+       kzfree(policy->hname);
+}
+
+/**
+ * __policy_find - find a policy by @name on a policy list
+ * @head: list to search  (NOT NULL)
+ * @name: name to search for  (NOT NULL)
+ *
+ * Requires: correct locks for the @head list be held
+ *
+ * Returns: unrefcounted policy that match @name or NULL if not found
+ */
+static struct aa_policy *__policy_find(struct list_head *head, const char *name)
+{
+       struct aa_policy *policy;
+
+       list_for_each_entry(policy, head, list) {
+               if (!strcmp(policy->name, name))
+                       return policy;
+       }
+       return NULL;
+}
+
+/**
+ * __policy_strn_find - find a policy that's name matches @len chars of @str
+ * @head: list to search  (NOT NULL)
+ * @str: string to search for  (NOT NULL)
+ * @len: length of match required
+ *
+ * Requires: correct locks for the @head list be held
+ *
+ * Returns: unrefcounted policy that match @str or NULL if not found
+ *
+ * if @len == strlen(@strlen) then this is equiv to __policy_find
+ * other wise it allows searching for policy by a partial match of name
+ */
+static struct aa_policy *__policy_strn_find(struct list_head *head,
+                                           const char *str, int len)
+{
+       struct aa_policy *policy;
+
+       list_for_each_entry(policy, head, list) {
+               if (aa_strneq(policy->name, str, len))
+                       return policy;
+       }
+
+       return NULL;
+}
+
+/*
+ * Routines for AppArmor namespaces
+ */
+
+static const char *hidden_ns_name = "---";
+/**
+ * aa_ns_visible - test if @view is visible from @curr
+ * @curr: namespace to treat as the parent (NOT NULL)
+ * @view:  namespace to test if visible from @curr (NOT NULL)
+ *
+ * Returns: true if @view is visible from @curr else false
+ */
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view)
+{
+       if (curr == view)
+               return true;
+
+       for ( ; view; view = view->parent) {
+               if (view->parent == curr)
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * aa_na_name - Find the ns name to display for @view from @curr
+ * @curr - current namespace (NOT NULL)
+ * @view - namespace attempting to view (NOT NULL)
+ *
+ * Returns: name of @view visible from @curr
+ */
+const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view)
+{
+       /* if view == curr then the namespace name isn't displayed */
+       if (curr == view)
+               return "";
+
+       if (aa_ns_visible(curr, view)) {
+               /* at this point if a ns is visible it is in a view ns
+                * thus the curr ns.hname is a prefix of its name.
+                * Only output the virtualized portion of the name
+                * Add + 2 to skip over // separating curr hname prefix
+                * from the visible tail of the views hname
+                */
+               return view->base.hname + strlen(curr->base.hname) + 2;
+       } else
+               return hidden_ns_name;
+}
+
+/**
+ * alloc_namespace - allocate, initialize and return a new namespace
+ * @prefix: parent namespace name (MAYBE NULL)
+ * @name: a preallocated name  (NOT NULL)
+ *
+ * Returns: refcounted namespace or NULL on failure.
+ */
+static struct aa_namespace *alloc_namespace(const char *prefix,
+                                           const char *name)
+{
+       struct aa_namespace *ns;
+
+       ns = kzalloc(sizeof(*ns), GFP_KERNEL);
+       AA_DEBUG("%s(%p)\n", __func__, ns);
+       if (!ns)
+               return NULL;
+       if (!policy_init(&ns->base, prefix, name))
+               goto fail_ns;
+
+       INIT_LIST_HEAD(&ns->sub_ns);
+       rwlock_init(&ns->lock);
+
+       /* released by free_namespace */
+       ns->unconfined = aa_alloc_profile("unconfined");
+       if (!ns->unconfined)
+               goto fail_unconfined;
+
+       ns->unconfined->sid = aa_alloc_sid();
+       ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
+           PFLAG_IMMUTABLE;
+
+       /*
+        * released by free_namespace, however __remove_namespace breaks
+        * the cyclic references (ns->unconfined, and unconfined->ns) and
+        * replaces with refs to parent namespace unconfined
+        */
+       ns->unconfined->ns = aa_get_namespace(ns);
+
+       return ns;
+
+fail_unconfined:
+       kzfree(ns->base.name);
+fail_ns:
+       kzfree(ns);
+       return NULL;
+}
+
+/**
+ * free_namespace - free a profile namespace
+ * @ns: the namespace to free  (MAYBE NULL)
+ *
+ * Requires: All references to the namespace must have been put, if the
+ *           namespace was referenced by a profile confining a task,
+ */
+static void free_namespace(struct aa_namespace *ns)
+{
+       if (!ns)
+               return;
+
+       policy_destroy(&ns->base);
+       aa_put_namespace(ns->parent);
+
+       if (ns->unconfined && ns->unconfined->ns == ns)
+               ns->unconfined->ns = NULL;
+
+       aa_put_profile(ns->unconfined);
+       kzfree(ns);
+}
+
+/**
+ * aa_free_namespace_kref - free aa_namespace by kref (see aa_put_namespace)
+ * @kr: kref callback for freeing of a namespace  (NOT NULL)
+ */
+void aa_free_namespace_kref(struct kref *kref)
+{
+       free_namespace(container_of(kref, struct aa_namespace, base.count));
+}
+
+/**
+ * __aa_find_namespace - find a namespace on a list by @name
+ * @head: list to search for namespace on  (NOT NULL)
+ * @name: name of namespace to look for  (NOT NULL)
+ *
+ * Returns: unrefcounted namespace
+ *
+ * Requires: ns lock be held
+ */
+static struct aa_namespace *__aa_find_namespace(struct list_head *head,
+                                               const char *name)
+{
+       return (struct aa_namespace *)__policy_find(head, name);
+}
+
+/**
+ * aa_find_namespace  -  look up a profile namespace on the namespace list
+ * @root: namespace to search in  (NOT NULL)
+ * @name: name of namespace to find  (NOT NULL)
+ *
+ * Returns: a refcounted namespace on the list, or NULL if no namespace
+ *          called @name exists.
+ *
+ * refcount released by caller
+ */
+struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
+                                      const char *name)
+{
+       struct aa_namespace *ns = NULL;
+
+       read_lock(&root->lock);
+       ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
+       read_unlock(&root->lock);
+
+       return ns;
+}
+
+/**
+ * aa_prepare_namespace - find an existing or create a new namespace of @name
+ * @name: the namespace to find or add  (MAYBE NULL)
+ *
+ * Returns: refcounted namespace or NULL if failed to create one
+ */
+static struct aa_namespace *aa_prepare_namespace(const char *name)
+{
+       struct aa_namespace *ns, *root;
+
+       root = aa_current_profile()->ns;
+
+       write_lock(&root->lock);
+
+       /* if name isn't specified the profile is loaded to the current ns */
+       if (!name) {
+               /* released by caller */
+               ns = aa_get_namespace(root);
+               goto out;
+       }
+
+       /* try and find the specified ns and if it doesn't exist create it */
+       /* released by caller */
+       ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
+       if (!ns) {
+               /* namespace not found */
+               struct aa_namespace *new_ns;
+               write_unlock(&root->lock);
+               new_ns = alloc_namespace(root->base.hname, name);
+               if (!new_ns)
+                       return NULL;
+               write_lock(&root->lock);
+               /* test for race when new_ns was allocated */
+               ns = __aa_find_namespace(&root->sub_ns, name);
+               if (!ns) {
+                       /* add parent ref */
+                       new_ns->parent = aa_get_namespace(root);
+
+                       list_add(&new_ns->base.list, &root->sub_ns);
+                       /* add list ref */
+                       ns = aa_get_namespace(new_ns);
+               } else {
+                       /* raced so free the new one */
+                       free_namespace(new_ns);
+                       /* get reference on namespace */
+                       aa_get_namespace(ns);
+               }
+       }
+out:
+       write_unlock(&root->lock);
+
+       /* return ref */
+       return ns;
+}
+
+/**
+ * __list_add_profile - add a profile to a list
+ * @list: list to add it to  (NOT NULL)
+ * @profile: the profile to add  (NOT NULL)
+ *
+ * refcount @profile, should be put by __list_remove_profile
+ *
+ * Requires: namespace lock be held, or list not be shared
+ */
+static void __list_add_profile(struct list_head *list,
+                              struct aa_profile *profile)
+{
+       list_add(&profile->base.list, list);
+       /* get list reference */
+       aa_get_profile(profile);
+}
+
+/**
+ * __list_remove_profile - remove a profile from the list it is on
+ * @profile: the profile to remove  (NOT NULL)
+ *
+ * remove a profile from the list, warning generally removal should
+ * be done with __replace_profile as most profile removals are
+ * replacements to the unconfined profile.
+ *
+ * put @profile list refcount
+ *
+ * Requires: namespace lock be held, or list not have been live
+ */
+static void __list_remove_profile(struct aa_profile *profile)
+{
+       list_del_init(&profile->base.list);
+       if (!(profile->flags & PFLAG_NO_LIST_REF))
+               /* release list reference */
+               aa_put_profile(profile);
+}
+
+/**
+ * __replace_profile - replace @old with @new on a list
+ * @old: profile to be replaced  (NOT NULL)
+ * @new: profile to replace @old with  (NOT NULL)
+ *
+ * Will duplicate and refcount elements that @new inherits from @old
+ * and will inherit @old children.
+ *
+ * refcount @new for list, put @old list refcount
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
+{
+       struct aa_policy *policy;
+       struct aa_profile *child, *tmp;
+
+       if (old->parent)
+               policy = &old->parent->base;
+       else
+               policy = &old->ns->base;
+
+       /* released when @new is freed */
+       new->parent = aa_get_profile(old->parent);
+       new->ns = aa_get_namespace(old->ns);
+       new->sid = old->sid;
+       __list_add_profile(&policy->profiles, new);
+       /* inherit children */
+       list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
+               aa_put_profile(child->parent);
+               child->parent = aa_get_profile(new);
+               /* list refcount transferred to @new*/
+               list_move(&child->base.list, &new->base.profiles);
+       }
+
+       /* released by free_profile */
+       old->replacedby = aa_get_profile(new);
+       __list_remove_profile(old);
+}
+
+static void __profile_list_release(struct list_head *head);
+
+/**
+ * __remove_profile - remove old profile, and children
+ * @profile: profile to be replaced  (NOT NULL)
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __remove_profile(struct aa_profile *profile)
+{
+       /* release any children lists first */
+       __profile_list_release(&profile->base.profiles);
+       /* released by free_profile */
+       profile->replacedby = aa_get_profile(profile->ns->unconfined);
+       __list_remove_profile(profile);
+}
+
+/**
+ * __profile_list_release - remove all profiles on the list and put refs
+ * @head: list of profiles  (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __profile_list_release(struct list_head *head)
+{
+       struct aa_profile *profile, *tmp;
+       list_for_each_entry_safe(profile, tmp, head, base.list)
+               __remove_profile(profile);
+}
+
+static void __ns_list_release(struct list_head *head);
+
+/**
+ * destroy_namespace - remove everything contained by @ns
+ * @ns: namespace to have it contents removed  (NOT NULL)
+ */
+static void destroy_namespace(struct aa_namespace *ns)
+{
+       if (!ns)
+               return;
+
+       write_lock(&ns->lock);
+       /* release all profiles in this namespace */
+       __profile_list_release(&ns->base.profiles);
+
+       /* release all sub namespaces */
+       __ns_list_release(&ns->sub_ns);
+
+       write_unlock(&ns->lock);
+}
+
+/**
+ * __remove_namespace - remove a namespace and all its children
+ * @ns: namespace to be removed  (NOT NULL)
+ *
+ * Requires: ns->parent->lock be held and ns removed from parent.
+ */
+static void __remove_namespace(struct aa_namespace *ns)
+{
+       struct aa_profile *unconfined = ns->unconfined;
+
+       /* remove ns from namespace list */
+       list_del_init(&ns->base.list);
+
+       /*
+        * break the ns, unconfined profile cyclic reference and forward
+        * all new unconfined profiles requests to the parent namespace
+        * This will result in all confined tasks that have a profile
+        * being removed, inheriting the parent->unconfined profile.
+        */
+       if (ns->parent)
+               ns->unconfined = aa_get_profile(ns->parent->unconfined);
+
+       destroy_namespace(ns);
+
+       /* release original ns->unconfined ref */
+       aa_put_profile(unconfined);
+       /* release ns->base.list ref, from removal above */
+       aa_put_namespace(ns);
+}
+
+/**
+ * __ns_list_release - remove all profile namespaces on the list put refs
+ * @head: list of profile namespaces  (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __ns_list_release(struct list_head *head)
+{
+       struct aa_namespace *ns, *tmp;
+       list_for_each_entry_safe(ns, tmp, head, base.list)
+               __remove_namespace(ns);
+
+}
+
+/**
+ * aa_alloc_root_ns - allocate the root profile namespace
+ *
+ * Returns: %0 on success else error
+ *
+ */
+int __init aa_alloc_root_ns(void)
+{
+       /* released by aa_free_root_ns - used as list ref*/
+       root_ns = alloc_namespace(NULL, "root");
+       if (!root_ns)
+               return -ENOMEM;
+
+       return 0;
+}
+
+ /**
+  * aa_free_root_ns - free the root profile namespace
+  */
+void __init aa_free_root_ns(void)
+ {
+        struct aa_namespace *ns = root_ns;
+        root_ns = NULL;
+
+        destroy_namespace(ns);
+        aa_put_namespace(ns);
+}
+
+/**
+ * aa_alloc_profile - allocate, initialize and return a new profile
+ * @hname: name of the profile  (NOT NULL)
+ *
+ * Returns: refcount profile or NULL on failure
+ */
+struct aa_profile *aa_alloc_profile(const char *hname)
+{
+       struct aa_profile *profile;
+
+       /* freed by free_profile - usually through aa_put_profile */
+       profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+       if (!profile)
+               return NULL;
+
+       if (!policy_init(&profile->base, NULL, hname)) {
+               kzfree(profile);
+               return NULL;
+       }
+
+       /* refcount released by caller */
+       return profile;
+}
+
+/**
+ * aa_new_null_profile - create a new null-X learning profile
+ * @parent: profile that caused this profile to be created (NOT NULL)
+ * @hat: true if the null- learning profile is a hat
+ *
+ * Create a null- complain mode profile used in learning mode.  The name of
+ * the profile is unique and follows the format of parent//null-sid.
+ *
+ * null profiles are added to the profile list but the list does not
+ * hold a count on them so that they are automatically released when
+ * not in use.
+ *
+ * Returns: new refcounted profile else NULL on failure
+ */
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
+{
+       struct aa_profile *profile = NULL;
+       char *name;
+       u32 sid = aa_alloc_sid();
+
+       /* freed below */
+       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
+       if (!name)
+               goto fail;
+       sprintf(name, "%s//null-%x", parent->base.hname, sid);
+
+       profile = aa_alloc_profile(name);
+       kfree(name);
+       if (!profile)
+               goto fail;
+
+       profile->sid = sid;
+       profile->mode = APPARMOR_COMPLAIN;
+       profile->flags = PFLAG_NULL;
+       if (hat)
+               profile->flags |= PFLAG_HAT;
+
+       /* released on free_profile */
+       profile->parent = aa_get_profile(parent);
+       profile->ns = aa_get_namespace(parent->ns);
+
+       write_lock(&profile->ns->lock);
+       __list_add_profile(&parent->base.profiles, profile);
+       write_unlock(&profile->ns->lock);
+
+       /* refcount released by caller */
+       return profile;
+
+fail:
+       aa_free_sid(sid);
+       return NULL;
+}
+
+/**
+ * free_profile - free a profile
+ * @profile: the profile to free  (MAYBE NULL)
+ *
+ * Free a profile, its hats and null_profile. All references to the profile,
+ * its hats and null_profile must have been put.
+ *
+ * If the profile was referenced from a task context, free_profile() will
+ * be called from an rcu callback routine, so we must not sleep here.
+ */
+static void free_profile(struct aa_profile *profile)
+{
+       AA_DEBUG("%s(%p)\n", __func__, profile);
+
+       if (!profile)
+               return;
+
+       if (!list_empty(&profile->base.list)) {
+               AA_ERROR("%s: internal error, "
+                        "profile '%s' still on ns list\n",
+                        __func__, profile->base.name);
+               BUG();
+       }
+
+       /* free children profiles */
+       policy_destroy(&profile->base);
+       aa_put_profile(profile->parent);
+
+       aa_put_namespace(profile->ns);
+       kzfree(profile->rename);
+
+       aa_free_file_rules(&profile->file);
+       aa_free_cap_rules(&profile->caps);
+       aa_free_rlimit_rules(&profile->rlimits);
+
+       aa_free_sid(profile->sid);
+       aa_put_dfa(profile->xmatch);
+
+       aa_put_profile(profile->replacedby);
+
+       kzfree(profile);
+}
+
+/**
+ * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
+ * @kr: kref callback for freeing of a profile  (NOT NULL)
+ */
+void aa_free_profile_kref(struct kref *kref)
+{
+       struct aa_profile *p = container_of(kref, struct aa_profile,
+                                           base.count);
+
+       free_profile(p);
+}
+
+/* TODO: profile accounting - setup in remove */
+
+/**
+ * __find_child - find a profile on @head list with a name matching @name
+ * @head: list to search  (NOT NULL)
+ * @name: name of profile (NOT NULL)
+ *
+ * Requires: ns lock protecting list be held
+ *
+ * Returns: unrefcounted profile ptr, or NULL if not found
+ */
+static struct aa_profile *__find_child(struct list_head *head, const char *name)
+{
+       return (struct aa_profile *)__policy_find(head, name);
+}
+
+/**
+ * __strn_find_child - find a profile on @head list using substring of @name
+ * @head: list to search  (NOT NULL)
+ * @name: name of profile (NOT NULL)
+ * @len: length of @name substring to match
+ *
+ * Requires: ns lock protecting list be held
+ *
+ * Returns: unrefcounted profile ptr, or NULL if not found
+ */
+static struct aa_profile *__strn_find_child(struct list_head *head,
+                                           const char *name, int len)
+{
+       return (struct aa_profile *)__policy_strn_find(head, name, len);
+}
+
+/**
+ * aa_find_child - find a profile by @name in @parent
+ * @parent: profile to search  (NOT NULL)
+ * @name: profile name to search for  (NOT NULL)
+ *
+ * Returns: a refcounted profile or NULL if not found
+ */
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
+{
+       struct aa_profile *profile;
+
+       read_lock(&parent->ns->lock);
+       profile = aa_get_profile(__find_child(&parent->base.profiles, name));
+       read_unlock(&parent->ns->lock);
+
+       /* refcount released by caller */
+       return profile;
+}
+
+/**
+ * __lookup_parent - lookup the parent of a profile of name @hname
+ * @ns: namespace to lookup profile in  (NOT NULL)
+ * @hname: hierarchical profile name to find parent of  (NOT NULL)
+ *
+ * Lookups up the parent of a fully qualified profile name, the profile
+ * that matches hname does not need to exist, in general this
+ * is used to load a new profile.
+ *
+ * Requires: ns->lock be held
+ *
+ * Returns: unrefcounted policy or NULL if not found
+ */
+static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
+                                        const char *hname)
+{
+       struct aa_policy *policy;
+       struct aa_profile *profile = NULL;
+       char *split;
+
+       policy = &ns->base;
+
+       for (split = strstr(hname, "//"); split;) {
+               profile = __strn_find_child(&policy->profiles, hname,
+                                           split - hname);
+               if (!profile)
+                       return NULL;
+               policy = &profile->base;
+               hname = split + 2;
+               split = strstr(hname, "//");
+       }
+       if (!profile)
+               return &ns->base;
+       return &profile->base;
+}
+
+/**
+ * __lookup_profile - lookup the profile matching @hname
+ * @base: base list to start looking up profile name from  (NOT NULL)
+ * @hname: hierarchical profile name  (NOT NULL)
+ *
+ * Requires: ns->lock be held
+ *
+ * Returns: unrefcounted profile pointer or NULL if not found
+ *
+ * Do a relative name lookup, recursing through profile tree.
+ */
+static struct aa_profile *__lookup_profile(struct aa_policy *base,
+                                          const char *hname)
+{
+       struct aa_profile *profile = NULL;
+       char *split;
+
+       for (split = strstr(hname, "//"); split;) {
+               profile = __strn_find_child(&base->profiles, hname,
+                                           split - hname);
+               if (!profile)
+                       return NULL;
+
+               base = &profile->base;
+               hname = split + 2;
+               split = strstr(hname, "//");
+       }
+
+       profile = __find_child(&base->profiles, hname);
+
+       return profile;
+}
+
+/**
+ * aa_lookup_profile - find a profile by its full or partial name
+ * @ns: the namespace to start from (NOT NULL)
+ * @hname: name to do lookup on.  Does not contain namespace prefix (NOT NULL)
+ *
+ * Returns: refcounted profile or NULL if not found
+ */
+struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
+{
+       struct aa_profile *profile;
+
+       read_lock(&ns->lock);
+       profile = aa_get_profile(__lookup_profile(&ns->base, hname));
+       read_unlock(&ns->lock);
+
+       /* refcount released by caller */
+       return profile;
+}
+
+/**
+ * replacement_allowed - test to see if replacement is allowed
+ * @profile: profile to test if it can be replaced  (MAYBE NULL)
+ * @noreplace: true if replacement shouldn't be allowed but addition is okay
+ * @info: Returns - info about why replacement failed (NOT NULL)
+ *
+ * Returns: %0 if replacement allowed else error code
+ */
+static int replacement_allowed(struct aa_profile *profile, int noreplace,
+                              const char **info)
+{
+       if (profile) {
+               if (profile->flags & PFLAG_IMMUTABLE) {
+                       *info = "cannot replace immutible profile";
+                       return -EPERM;
+               } else if (noreplace) {
+                       *info = "profile already exists";
+                       return -EEXIST;
+               }
+       }
+       return 0;
+}
+
+/**
+ * __add_new_profile - simple wrapper around __list_add_profile
+ * @ns: namespace that profile is being added to  (NOT NULL)
+ * @policy: the policy container to add the profile to  (NOT NULL)
+ * @profile: profile to add  (NOT NULL)
+ *
+ * add a profile to a list and do other required basic allocations
+ */
+static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
+                             struct aa_profile *profile)
+{
+       if (policy != &ns->base)
+               /* released on profile replacement or free_profile */
+               profile->parent = aa_get_profile((struct aa_profile *) policy);
+       __list_add_profile(&policy->profiles, profile);
+       /* released on free_profile */
+       profile->sid = aa_alloc_sid();
+       profile->ns = aa_get_namespace(ns);
+}
+
+/**
+ * aa_audit_policy - Do auditing of policy changes
+ * @op: policy operation being performed
+ * @gfp: memory allocation flags
+ * @name: name of profile being manipulated (NOT NULL)
+ * @info: any extra information to be audited (MAYBE NULL)
+ * @error: error code
+ *
+ * Returns: the error to be returned after audit is done
+ */
+static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
+                       int error)
+{
+       struct common_audit_data sa;
+       COMMON_AUDIT_DATA_INIT(&sa, NONE);
+       sa.aad.op = op;
+       sa.aad.name = name;
+       sa.aad.info = info;
+       sa.aad.error = error;
+
+       return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
+                       &sa, NULL);
+}
+
+/**
+ * aa_may_manage_policy - can the current task manage policy
+ * @op: the policy manipulation operation being done
+ *
+ * Returns: true if the task is allowed to manipulate policy
+ */
+bool aa_may_manage_policy(int op)
+{
+       /* check if loading policy is locked out */
+       if (aa_g_lock_policy) {
+               audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES);
+               return 0;
+       }
+
+       if (!capable(CAP_MAC_ADMIN)) {
+               audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * aa_replace_profiles - replace profile(s) on the profile list
+ * @udata: serialized data stream  (NOT NULL)
+ * @size: size of the serialized data stream
+ * @noreplace: true if only doing addition, no replacement allowed
+ *
+ * unpack and replace a profile on the profile list and uses of that profile
+ * by any aa_task_cxt.  If the profile does not exist on the profile list
+ * it is added.
+ *
+ * Returns: size of data consumed else error code on failure.
+ */
+ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
+{
+       struct aa_policy *policy;
+       struct aa_profile *old_profile = NULL, *new_profile = NULL;
+       struct aa_profile *rename_profile = NULL;
+       struct aa_namespace *ns = NULL;
+       const char *ns_name, *name = NULL, *info = NULL;
+       int op = OP_PROF_REPL;
+       ssize_t error;
+
+       /* released below */
+       new_profile = aa_unpack(udata, size, &ns_name);
+       if (IS_ERR(new_profile)) {
+               error = PTR_ERR(new_profile);
+               new_profile = NULL;
+               goto fail;
+       }
+
+       /* released below */
+       ns = aa_prepare_namespace(ns_name);
+       if (!ns) {
+               info = "failed to prepare namespace";
+               error = -ENOMEM;
+               name = ns_name;
+               goto fail;
+       }
+
+       name = new_profile->base.hname;
+
+       write_lock(&ns->lock);
+       /* no ref on policy only use inside lock */
+       policy = __lookup_parent(ns, new_profile->base.hname);
+
+       if (!policy) {
+               info = "parent does not exist";
+               error = -ENOENT;
+               goto audit;
+       }
+
+       old_profile = __find_child(&policy->profiles, new_profile->base.name);
+       /* released below */
+       aa_get_profile(old_profile);
+
+       if (new_profile->rename) {
+               rename_profile = __lookup_profile(&ns->base,
+                                                 new_profile->rename);
+               /* released below */
+               aa_get_profile(rename_profile);
+
+               if (!rename_profile) {
+                       info = "profile to rename does not exist";
+                       name = new_profile->rename;
+                       error = -ENOENT;
+                       goto audit;
+               }
+       }
+
+       error = replacement_allowed(old_profile, noreplace, &info);
+       if (error)
+               goto audit;
+
+       error = replacement_allowed(rename_profile, noreplace, &info);
+       if (error)
+               goto audit;
+
+audit:
+       if (!old_profile && !rename_profile)
+               op = OP_PROF_LOAD;
+
+       error = audit_policy(op, GFP_ATOMIC, name, info, error);
+
+       if (!error) {
+               if (rename_profile)
+                       __replace_profile(rename_profile, new_profile);
+               if (old_profile) {
+                       /* when there are both rename and old profiles
+                        * inherit old profiles sid
+                        */
+                       if (rename_profile)
+                               aa_free_sid(new_profile->sid);
+                       __replace_profile(old_profile, new_profile);
+               }
+               if (!(old_profile || rename_profile))
+                       __add_new_profile(ns, policy, new_profile);
+       }
+       write_unlock(&ns->lock);
+
+out:
+       aa_put_namespace(ns);
+       aa_put_profile(rename_profile);
+       aa_put_profile(old_profile);
+       aa_put_profile(new_profile);
+       if (error)
+               return error;
+       return size;
+
+fail:
+       error = audit_policy(op, GFP_KERNEL, name, info, error);
+       goto out;
+}
+
+/**
+ * aa_remove_profiles - remove profile(s) from the system
+ * @fqname: name of the profile or namespace to remove  (NOT NULL)
+ * @size: size of the name
+ *
+ * Remove a profile or sub namespace from the current namespace, so that
+ * they can not be found anymore and mark them as replaced by unconfined
+ *
+ * NOTE: removing confinement does not restore rlimits to preconfinemnet values
+ *
+ * Returns: size of data consume else error code if fails
+ */
+ssize_t aa_remove_profiles(char *fqname, size_t size)
+{
+       struct aa_namespace *root, *ns = NULL;
+       struct aa_profile *profile = NULL;
+       const char *name = fqname, *info = NULL;
+       ssize_t error = 0;
+
+       if (*fqname == 0) {
+               info = "no profile specified";
+               error = -ENOENT;
+               goto fail;
+       }
+
+       root = aa_current_profile()->ns;
+
+       if (fqname[0] == ':') {
+               char *ns_name;
+               name = aa_split_fqname(fqname, &ns_name);
+               if (ns_name) {
+                       /* released below */
+                       ns = aa_find_namespace(root, ns_name);
+                       if (!ns) {
+                               info = "namespace does not exist";
+                               error = -ENOENT;
+                               goto fail;
+                       }
+               }
+       } else
+               /* released below */
+               ns = aa_get_namespace(root);
+
+       write_lock(&ns->lock);
+       if (!name) {
+               /* remove namespace - can only happen if fqname[0] == ':' */
+               __remove_namespace(ns);
+       } else {
+               /* remove profile */
+               profile = aa_get_profile(__lookup_profile(&ns->base, name));
+               if (!profile) {
+                       error = -ENOENT;
+                       info = "profile does not exist";
+                       goto fail_ns_lock;
+               }
+               name = profile->base.hname;
+               __remove_profile(profile);
+       }
+       write_unlock(&ns->lock);
+
+       /* don't fail removal if audit fails */
+       (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+       aa_put_namespace(ns);
+       aa_put_profile(profile);
+       return size;
+
+fail_ns_lock:
+       write_unlock(&ns->lock);
+       aa_put_namespace(ns);
+
+fail:
+       (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+       return error;
+}
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
new file mode 100644 (file)
index 0000000..eb3700e
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor functions for unpacking policy loaded from
+ * userspace.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ *
+ * AppArmor uses a serialized binary format for loading policy.
+ * To find policy format documentation look in Documentation/apparmor.txt
+ * All policy is validated before it is used.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/match.h"
+#include "include/policy.h"
+#include "include/policy_unpack.h"
+#include "include/sid.h"
+
+/*
+ * The AppArmor interface treats data as a type byte followed by the
+ * actual data.  The interface has the notion of a a named entry
+ * which has a name (AA_NAME typecode followed by name string) followed by
+ * the entries typecode and data.  Named types allow for optional
+ * elements and extensions to be added and tested for without breaking
+ * backwards compatibility.
+ */
+
+enum aa_code {
+       AA_U8,
+       AA_U16,
+       AA_U32,
+       AA_U64,
+       AA_NAME,                /* same as string except it is items name */
+       AA_STRING,
+       AA_BLOB,
+       AA_STRUCT,
+       AA_STRUCTEND,
+       AA_LIST,
+       AA_LISTEND,
+       AA_ARRAY,
+       AA_ARRAYEND,
+};
+
+/*
+ * aa_ext is the read of the buffer containing the serialized profile.  The
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
+ * the unpack routines.
+ */
+struct aa_ext {
+       void *start;
+       void *end;
+       void *pos;              /* pointer to current position in the buffer */
+       u32 version;
+};
+
+/* audit callback for unpack fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+       if (sa->aad.iface.target) {
+               struct aa_profile *name = sa->aad.iface.target;
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, name->base.hname);
+       }
+       if (sa->aad.iface.pos)
+               audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);
+}
+
+/**
+ * audit_iface - do audit message for policy unpacking/load/replace/remove
+ * @new: profile if it has been allocated (MAYBE NULL)
+ * @name: name of the profile being manipulated (MAYBE NULL)
+ * @info: any extra info about the failure (MAYBE NULL)
+ * @e: buffer position info (NOT NULL)
+ * @error: error code
+ *
+ * Returns: %0 or error
+ */
+static int audit_iface(struct aa_profile *new, const char *name,
+                      const char *info, struct aa_ext *e, int error)
+{
+       struct aa_profile *profile = __aa_current_profile();
+       struct common_audit_data sa;
+       COMMON_AUDIT_DATA_INIT(&sa, NONE);
+       sa.aad.iface.pos = e->pos - e->start;
+       sa.aad.iface.target = new;
+       sa.aad.name = name;
+       sa.aad.info = info;
+       sa.aad.error = error;
+
+       return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
+                       audit_cb);
+}
+
+/* test if read will be in packed data bounds */
+static bool inbounds(struct aa_ext *e, size_t size)
+{
+       return (size <= e->end - e->pos);
+}
+
+/**
+ * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
+ * @e: serialized data read head (NOT NULL)
+ * @chunk: start address for chunk of data (NOT NULL)
+ *
+ * Returns: the size of chunk found with the read head at the end of the chunk.
+ */
+static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
+{
+       size_t size = 0;
+
+       if (!inbounds(e, sizeof(u16)))
+               return 0;
+       size = le16_to_cpu(get_unaligned((u16 *) e->pos));
+       e->pos += sizeof(u16);
+       if (!inbounds(e, size))
+               return 0;
+       *chunk = e->pos;
+       e->pos += size;
+       return size;
+}
+
+/* unpack control byte */
+static bool unpack_X(struct aa_ext *e, enum aa_code code)
+{
+       if (!inbounds(e, 1))
+               return 0;
+       if (*(u8 *) e->pos != code)
+               return 0;
+       e->pos++;
+       return 1;
+}
+
+/**
+ * unpack_nameX - check is the next element is of type X with a name of @name
+ * @e: serialized data extent information  (NOT NULL)
+ * @code: type code
+ * @name: name to match to the serialized element.  (MAYBE NULL)
+ *
+ * check that the next serialized data element is of type X and has a tag
+ * name @name.  If @name is specified then there must be a matching
+ * name element in the stream.  If @name is NULL any name element will be
+ * skipped and only the typecode will be tested.
+ *
+ * Returns 1 on success (both type code and name tests match) and the read
+ * head is advanced past the headers
+ *
+ * Returns: 0 if either match fails, the read head does not move
+ */
+static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+{
+       /*
+        * May need to reset pos if name or type doesn't match
+        */
+       void *pos = e->pos;
+       /*
+        * Check for presence of a tagname, and if present name size
+        * AA_NAME tag value is a u16.
+        */
+       if (unpack_X(e, AA_NAME)) {
+               char *tag = NULL;
+               size_t size = unpack_u16_chunk(e, &tag);
+               /* if a name is specified it must match. otherwise skip tag */
+               if (name && (!size || strcmp(name, tag)))
+                       goto fail;
+       } else if (name) {
+               /* if a name is specified and there is no name tag fail */
+               goto fail;
+       }
+
+       /* now check if type code matches */
+       if (unpack_X(e, code))
+               return 1;
+
+fail:
+       e->pos = pos;
+       return 0;
+}
+
+static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
+{
+       if (unpack_nameX(e, AA_U32, name)) {
+               if (!inbounds(e, sizeof(u32)))
+                       return 0;
+               if (data)
+                       *data = le32_to_cpu(get_unaligned((u32 *) e->pos));
+               e->pos += sizeof(u32);
+               return 1;
+       }
+       return 0;
+}
+
+static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
+{
+       if (unpack_nameX(e, AA_U64, name)) {
+               if (!inbounds(e, sizeof(u64)))
+                       return 0;
+               if (data)
+                       *data = le64_to_cpu(get_unaligned((u64 *) e->pos));
+               e->pos += sizeof(u64);
+               return 1;
+       }
+       return 0;
+}
+
+static size_t unpack_array(struct aa_ext *e, const char *name)
+{
+       if (unpack_nameX(e, AA_ARRAY, name)) {
+               int size;
+               if (!inbounds(e, sizeof(u16)))
+                       return 0;
+               size = (int)le16_to_cpu(get_unaligned((u16 *) e->pos));
+               e->pos += sizeof(u16);
+               return size;
+       }
+       return 0;
+}
+
+static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
+{
+       if (unpack_nameX(e, AA_BLOB, name)) {
+               u32 size;
+               if (!inbounds(e, sizeof(u32)))
+                       return 0;
+               size = le32_to_cpu(get_unaligned((u32 *) e->pos));
+               e->pos += sizeof(u32);
+               if (inbounds(e, (size_t) size)) {
+                       *blob = e->pos;
+                       e->pos += size;
+                       return size;
+               }
+       }
+       return 0;
+}
+
+static int unpack_str(struct aa_ext *e, const char **string, const char *name)
+{
+       char *src_str;
+       size_t size = 0;
+       void *pos = e->pos;
+       *string = NULL;
+       if (unpack_nameX(e, AA_STRING, name)) {
+               size = unpack_u16_chunk(e, &src_str);
+               if (size) {
+                       /* strings are null terminated, length is size - 1 */
+                       if (src_str[size - 1] != 0)
+                               goto fail;
+                       *string = src_str;
+               }
+       }
+       return size;
+
+fail:
+       e->pos = pos;
+       return 0;
+}
+
+static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
+{
+       const char *tmp;
+       void *pos = e->pos;
+       int res = unpack_str(e, &tmp, name);
+       *string = NULL;
+
+       if (!res)
+               return 0;
+
+       *string = kmemdup(tmp, res, GFP_KERNEL);
+       if (!*string) {
+               e->pos = pos;
+               return 0;
+       }
+
+       return res;
+}
+
+/**
+ * verify_accept - verify the accept tables of a dfa
+ * @dfa: dfa to verify accept tables of (NOT NULL)
+ * @flags: flags governing dfa
+ *
+ * Returns: 1 if valid accept tables else 0 if error
+ */
+static bool verify_accept(struct aa_dfa *dfa, int flags)
+{
+       int i;
+
+       /* verify accept permissions */
+       for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
+               int mode = ACCEPT_TABLE(dfa)[i];
+
+               if (mode & ~DFA_VALID_PERM_MASK)
+                       return 0;
+
+               if (ACCEPT_TABLE2(dfa)[i] & ~DFA_VALID_PERM2_MASK)
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * unpack_dfa - unpack a file rule dfa
+ * @e: serialized data extent information (NOT NULL)
+ *
+ * returns dfa or ERR_PTR or NULL if no dfa
+ */
+static struct aa_dfa *unpack_dfa(struct aa_ext *e)
+{
+       char *blob = NULL;
+       size_t size;
+       struct aa_dfa *dfa = NULL;
+
+       size = unpack_blob(e, &blob, "aadfa");
+       if (size) {
+               /*
+                * The dfa is aligned with in the blob to 8 bytes
+                * from the beginning of the stream.
+                */
+               size_t sz = blob - (char *)e->start;
+               size_t pad = ALIGN(sz, 8) - sz;
+               int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
+                       TO_ACCEPT2_FLAG(YYTD_DATA32);
+
+
+               if (aa_g_paranoid_load)
+                       flags |= DFA_FLAG_VERIFY_STATES;
+
+               dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
+
+               if (IS_ERR(dfa))
+                       return dfa;
+
+               if (!verify_accept(dfa, flags))
+                       goto fail;
+       }
+
+       return dfa;
+
+fail:
+       aa_put_dfa(dfa);
+       return ERR_PTR(-EPROTO);
+}
+
+/**
+ * unpack_trans_table - unpack a profile transition table
+ * @e: serialized data extent information  (NOT NULL)
+ * @profile: profile to add the accept table to (NOT NULL)
+ *
+ * Returns: 1 if table succesfully unpacked
+ */
+static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
+{
+       void *pos = e->pos;
+
+       /* exec table is optional */
+       if (unpack_nameX(e, AA_STRUCT, "xtable")) {
+               int i, size;
+
+               size = unpack_array(e, NULL);
+               /* currently 4 exec bits and entries 0-3 are reserved iupcx */
+               if (size > 16 - 4)
+                       goto fail;
+               profile->file.trans.table = kzalloc(sizeof(char *) * size,
+                                                   GFP_KERNEL);
+               if (!profile->file.trans.table)
+                       goto fail;
+
+               profile->file.trans.size = size;
+               for (i = 0; i < size; i++) {
+                       char *str;
+                       int c, j, size = unpack_strdup(e, &str, NULL);
+                       /* unpack_strdup verifies that the last character is
+                        * null termination byte.
+                        */
+                       if (!size)
+                               goto fail;
+                       profile->file.trans.table[i] = str;
+                       /* verify that name doesn't start with space */
+                       if (isspace(*str))
+                               goto fail;
+
+                       /* count internal #  of internal \0 */
+                       for (c = j = 0; j < size - 2; j++) {
+                               if (!str[j])
+                                       c++;
+                       }
+                       if (*str == ':') {
+                               /* beginning with : requires an embedded \0,
+                                * verify that exactly 1 internal \0 exists
+                                * trailing \0 already verified by unpack_strdup
+                                */
+                               if (c != 1)
+                                       goto fail;
+                               /* first character after : must be valid */
+                               if (!str[1])
+                                       goto fail;
+                       } else if (c)
+                               /* fail - all other cases with embedded \0 */
+                               goto fail;
+               }
+               if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+                       goto fail;
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
+       }
+       return 1;
+
+fail:
+       aa_free_domain_entries(&profile->file.trans);
+       e->pos = pos;
+       return 0;
+}
+
+static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
+{
+       void *pos = e->pos;
+
+       /* rlimits are optional */
+       if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
+               int i, size;
+               u32 tmp = 0;
+               if (!unpack_u32(e, &tmp, NULL))
+                       goto fail;
+               profile->rlimits.mask = tmp;
+
+               size = unpack_array(e, NULL);
+               if (size > RLIM_NLIMITS)
+                       goto fail;
+               for (i = 0; i < size; i++) {
+                       u64 tmp = 0;
+                       int a = aa_map_resource(i);
+                       if (!unpack_u64(e, &tmp, NULL))
+                               goto fail;
+                       profile->rlimits.limits[a].rlim_max = tmp;
+               }
+               if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+                       goto fail;
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
+       }
+       return 1;
+
+fail:
+       e->pos = pos;
+       return 0;
+}
+
+/**
+ * unpack_profile - unpack a serialized profile
+ * @e: serialized data extent information (NOT NULL)
+ *
+ * NOTE: unpack profile sets audit struct if there is a failure
+ */
+static struct aa_profile *unpack_profile(struct aa_ext *e)
+{
+       struct aa_profile *profile = NULL;
+       const char *name = NULL;
+       int error = -EPROTO;
+       kernel_cap_t tmpcap;
+       u32 tmp;
+
+       /* check that we have the right struct being passed */
+       if (!unpack_nameX(e, AA_STRUCT, "profile"))
+               goto fail;
+       if (!unpack_str(e, &name, NULL))
+               goto fail;
+
+       profile = aa_alloc_profile(name);
+       if (!profile)
+               return ERR_PTR(-ENOMEM);
+
+       /* profile renaming is optional */
+       (void) unpack_str(e, &profile->rename, "rename");
+
+       /* xmatch is optional and may be NULL */
+       profile->xmatch = unpack_dfa(e);
+       if (IS_ERR(profile->xmatch)) {
+               error = PTR_ERR(profile->xmatch);
+               profile->xmatch = NULL;
+               goto fail;
+       }
+       /* xmatch_len is not optional if xmatch is set */
+       if (profile->xmatch) {
+               if (!unpack_u32(e, &tmp, NULL))
+                       goto fail;
+               profile->xmatch_len = tmp;
+       }
+
+       /* per profile debug flags (complain, audit) */
+       if (!unpack_nameX(e, AA_STRUCT, "flags"))
+               goto fail;
+       if (!unpack_u32(e, &tmp, NULL))
+               goto fail;
+       if (tmp)
+               profile->flags |= PFLAG_HAT;
+       if (!unpack_u32(e, &tmp, NULL))
+               goto fail;
+       if (tmp)
+               profile->mode = APPARMOR_COMPLAIN;
+       if (!unpack_u32(e, &tmp, NULL))
+               goto fail;
+       if (tmp)
+               profile->audit = AUDIT_ALL;
+
+       if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+               goto fail;
+
+       /* path_flags is optional */
+       if (unpack_u32(e, &profile->path_flags, "path_flags"))
+               profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED;
+       else
+               /* set a default value if path_flags field is not present */
+               profile->path_flags = PFLAG_MEDIATE_DELETED;
+
+       if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
+               goto fail;
+       if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
+               goto fail;
+       if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
+               goto fail;
+       if (!unpack_u32(e, &tmpcap.cap[0], NULL))
+               goto fail;
+
+       if (unpack_nameX(e, AA_STRUCT, "caps64")) {
+               /* optional upper half of 64 bit caps */
+               if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
+                       goto fail;
+               if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
+                       goto fail;
+               if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
+                       goto fail;
+               if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
+                       goto fail;
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
+       }
+
+       if (unpack_nameX(e, AA_STRUCT, "capsx")) {
+               /* optional extended caps mediation mask */
+               if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
+                       goto fail;
+               if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
+                       goto fail;
+       }
+
+       if (!unpack_rlimits(e, profile))
+               goto fail;
+
+       /* get file rules */
+       profile->file.dfa = unpack_dfa(e);
+       if (IS_ERR(profile->file.dfa)) {
+               error = PTR_ERR(profile->file.dfa);
+               profile->file.dfa = NULL;
+               goto fail;
+       }
+
+       if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+               /* default start state */
+               profile->file.start = DFA_START;
+
+       if (!unpack_trans_table(e, profile))
+               goto fail;
+
+       if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+               goto fail;
+
+       return profile;
+
+fail:
+       if (profile)
+               name = NULL;
+       else if (!name)
+               name = "unknown";
+       audit_iface(profile, name, "failed to unpack profile", e, error);
+       aa_put_profile(profile);
+
+       return ERR_PTR(error);
+}
+
+/**
+ * verify_head - unpack serialized stream header
+ * @e: serialized data read head (NOT NULL)
+ * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
+ *
+ * Returns: error or 0 if header is good
+ */
+static int verify_header(struct aa_ext *e, const char **ns)
+{
+       int error = -EPROTONOSUPPORT;
+       /* get the interface version */
+       if (!unpack_u32(e, &e->version, "version")) {
+               audit_iface(NULL, NULL, "invalid profile format", e, error);
+               return error;
+       }
+
+       /* check that the interface version is currently supported */
+       if (e->version != 5) {
+               audit_iface(NULL, NULL, "unsupported interface version", e,
+                           error);
+               return error;
+       }
+
+       /* read the namespace if present */
+       if (!unpack_str(e, ns, "namespace"))
+               *ns = NULL;
+
+       return 0;
+}
+
+static bool verify_xindex(int xindex, int table_size)
+{
+       int index, xtype;
+       xtype = xindex & AA_X_TYPE_MASK;
+       index = xindex & AA_X_INDEX_MASK;
+       if (xtype == AA_X_TABLE && index > table_size)
+               return 0;
+       return 1;
+}
+
+/* verify dfa xindexes are in range of transition tables */
+static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
+{
+       int i;
+       for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
+               if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))
+                       return 0;
+               if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * verify_profile - Do post unpack analysis to verify profile consistency
+ * @profile: profile to verify (NOT NULL)
+ *
+ * Returns: 0 if passes verification else error
+ */
+static int verify_profile(struct aa_profile *profile)
+{
+       if (aa_g_paranoid_load) {
+               if (profile->file.dfa &&
+                   !verify_dfa_xindex(profile->file.dfa,
+                                      profile->file.trans.size)) {
+                       audit_iface(profile, NULL, "Invalid named transition",
+                                   NULL, -EPROTO);
+                       return -EPROTO;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * aa_unpack - unpack packed binary profile data loaded from user space
+ * @udata: user data copied to kmem  (NOT NULL)
+ * @size: the size of the user data
+ * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
+ *
+ * Unpack user data and return refcounted allocated profile or ERR_PTR
+ *
+ * Returns: profile else error pointer if fails to unpack
+ */
+struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
+{
+       struct aa_profile *profile = NULL;
+       int error;
+       struct aa_ext e = {
+               .start = udata,
+               .end = udata + size,
+               .pos = udata,
+       };
+
+       error = verify_header(&e, ns);
+       if (error)
+               return ERR_PTR(error);
+
+       profile = unpack_profile(&e);
+       if (IS_ERR(profile))
+               return profile;
+
+       error = verify_profile(profile);
+       if (error) {
+               aa_put_profile(profile);
+               profile = ERR_PTR(error);
+       }
+
+       /* return refcount */
+       return profile;
+}
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
new file mode 100644 (file)
index 0000000..04a2cf8
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /proc/<pid>/attr/ interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/context.h"
+#include "include/policy.h"
+#include "include/domain.h"
+
+
+/**
+ * aa_getprocattr - Return the profile information for @profile
+ * @profile: the profile to print profile info about  (NOT NULL)
+ * @string: Returns - string containing the profile info (NOT NULL)
+ *
+ * Returns: length of @string on success else error on failure
+ *
+ * Requires: profile != NULL
+ *
+ * Creates a string containing the namespace_name://profile_name for
+ * @profile.
+ *
+ * Returns: size of string placed in @string else error code on failure
+ */
+int aa_getprocattr(struct aa_profile *profile, char **string)
+{
+       char *str;
+       int len = 0, mode_len = 0, ns_len = 0, name_len;
+       const char *mode_str = profile_mode_names[profile->mode];
+       const char *ns_name = NULL;
+       struct aa_namespace *ns = profile->ns;
+       struct aa_namespace *current_ns = __aa_current_profile()->ns;
+       char *s;
+
+       if (!aa_ns_visible(current_ns, ns))
+               return -EACCES;
+
+       ns_name = aa_ns_name(current_ns, ns);
+       ns_len = strlen(ns_name);
+
+       /* if the visible ns_name is > 0 increase size for : :// seperator */
+       if (ns_len)
+               ns_len += 4;
+
+       /* unconfined profiles don't have a mode string appended */
+       if (!unconfined(profile))
+               mode_len = strlen(mode_str) + 3;        /* + 3 for _() */
+
+       name_len = strlen(profile->base.hname);
+       len = mode_len + ns_len + name_len + 1;     /* + 1 for \n */
+       s = str = kmalloc(len + 1, GFP_KERNEL);     /* + 1 \0 */
+       if (!str)
+               return -ENOMEM;
+
+       if (ns_len) {
+               /* skip over prefix current_ns->base.hname and separating // */
+               sprintf(s, ":%s://", ns_name);
+               s += ns_len;
+       }
+       if (unconfined(profile))
+               /* mode string not being appended */
+               sprintf(s, "%s\n", profile->base.hname);
+       else
+               sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
+       *string = str;
+
+       /* NOTE: len does not include \0 of string, not saved as part of file */
+       return len;
+}
+
+/**
+ * split_token_from_name - separate a string of form  <token>^<name>
+ * @op: operation being checked
+ * @args: string to parse  (NOT NULL)
+ * @token: stores returned parsed token value  (NOT NULL)
+ *
+ * Returns: start position of name after token else NULL on failure
+ */
+static char *split_token_from_name(int op, char *args, u64 * token)
+{
+       char *name;
+
+       *token = simple_strtoull(args, &name, 16);
+       if ((name == args) || *name != '^') {
+               AA_ERROR("%s: Invalid input '%s'", op_table[op], args);
+               return ERR_PTR(-EINVAL);
+       }
+
+       name++;                 /* skip ^ */
+       if (!*name)
+               name = NULL;
+       return name;
+}
+
+/**
+ * aa_setprocattr_chagnehat - handle procattr interface to change_hat
+ * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
+ * @size: size of the args
+ * @test: true if this is a test of change_hat permissions
+ *
+ * Returns: %0 or error code if change_hat fails
+ */
+int aa_setprocattr_changehat(char *args, size_t size, int test)
+{
+       char *hat;
+       u64 token;
+       const char *hats[16];           /* current hard limit on # of names */
+       int count = 0;
+
+       hat = split_token_from_name(OP_CHANGE_HAT, args, &token);
+       if (IS_ERR(hat))
+               return PTR_ERR(hat);
+
+       if (!hat && !token) {
+               AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
+               return -EINVAL;
+       }
+
+       if (hat) {
+               /* set up hat name vector, args guaranteed null terminated
+                * at args[size] by setprocattr.
+                *
+                * If there are multiple hat names in the buffer each is
+                * separated by a \0.  Ie. userspace writes them pre tokenized
+                */
+               char *end = args + size;
+               for (count = 0; (hat < end) && count < 16; ++count) {
+                       char *next = hat + strlen(hat) + 1;
+                       hats[count] = hat;
+                       hat = next;
+               }
+       }
+
+       AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
+                __func__, token, hat ? hat : NULL);
+
+       return aa_change_hat(hats, count, token, test);
+}
+
+/**
+ * aa_setprocattr_changeprofile - handle procattr interface to changeprofile
+ * @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)
+ * @onexec: true if change_profile should be delayed until exec
+ * @test: true if this is a test of change_profile permissions
+ *
+ * Returns: %0 or error code if change_profile fails
+ */
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
+{
+       char *name, *ns_name;
+
+       name = aa_split_fqname(fqname, &ns_name);
+       return aa_change_profile(ns_name, name, onexec, test);
+}
+
+int aa_setprocattr_permipc(char *fqname)
+{
+       /* TODO: add ipc permission querying */
+       return -ENOTSUPP;
+}
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
new file mode 100644 (file)
index 0000000..4a368f1
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor resource mediation and attachment
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/audit.h>
+
+#include "include/audit.h"
+#include "include/resource.h"
+#include "include/policy.h"
+
+/*
+ * Table of rlimit names: we generate it from resource.h.
+ */
+#include "rlim_names.h"
+
+/* audit callback for resource specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+
+       audit_log_format(ab, " rlimit=%s value=%lu",
+                        rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max);
+}
+
+/**
+ * audit_resource - audit setting resource limit
+ * @profile: profile being enforced  (NOT NULL)
+ * @resoure: rlimit being auditing
+ * @value: value being set
+ * @error: error value
+ *
+ * Returns: 0 or sa->error else other error code on failure
+ */
+static int audit_resource(struct aa_profile *profile, unsigned int resource,
+                         unsigned long value, int error)
+{
+       struct common_audit_data sa;
+
+       COMMON_AUDIT_DATA_INIT(&sa, NONE);
+       sa.aad.op = OP_SETRLIMIT,
+       sa.aad.rlim.rlim = resource;
+       sa.aad.rlim.max = value;
+       sa.aad.error = error;
+       return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
+                       audit_cb);
+}
+
+/**
+ * aa_map_resouce - map compiled policy resource to internal #
+ * @resource: flattened policy resource number
+ *
+ * Returns: resource # for the current architecture.
+ *
+ * rlimit resource can vary based on architecture, map the compiled policy
+ * resource # to the internal representation for the architecture.
+ */
+int aa_map_resource(int resource)
+{
+       return rlim_map[resource];
+}
+
+/**
+ * aa_task_setrlimit - test permission to set an rlimit
+ * @profile - profile confining the task  (NOT NULL)
+ * @resource - the resource being set
+ * @new_rlim - the new resource limit  (NOT NULL)
+ *
+ * Control raising the processes hard limit.
+ *
+ * Returns: 0 or error code if setting resource failed
+ */
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+                     struct rlimit *new_rlim)
+{
+       int error = 0;
+
+       if (profile->rlimits.mask & (1 << resource) &&
+           new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)
+
+               error = audit_resource(profile, resource, new_rlim->rlim_max,
+                       -EACCES);
+
+       return error;
+}
+
+/**
+ * __aa_transition_rlimits - apply new profile rlimits
+ * @old: old profile on task  (NOT NULL)
+ * @new: new profile with rlimits to apply  (NOT NULL)
+ */
+void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
+{
+       unsigned int mask = 0;
+       struct rlimit *rlim, *initrlim;
+       int i;
+
+       /* for any rlimits the profile controlled reset the soft limit
+        * to the less of the tasks hard limit and the init tasks soft limit
+        */
+       if (old->rlimits.mask) {
+               for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+                       if (old->rlimits.mask & mask) {
+                               rlim = current->signal->rlim + i;
+                               initrlim = init_task.signal->rlim + i;
+                               rlim->rlim_cur = min(rlim->rlim_max,
+                                                    initrlim->rlim_cur);
+                       }
+               }
+       }
+
+       /* set any new hard limits as dictated by the new profile */
+       if (!new->rlimits.mask)
+               return;
+       for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+               if (!(new->rlimits.mask & mask))
+                       continue;
+
+               rlim = current->signal->rlim + i;
+               rlim->rlim_max = min(rlim->rlim_max,
+                                    new->rlimits.limits[i].rlim_max);
+               /* soft limit should not exceed hard limit */
+               rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+       }
+}
diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c
new file mode 100644 (file)
index 0000000..f0b34f7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (sid) manipulation fns
+ *
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; 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.
+ *
+ *
+ * AppArmor allocates a unique sid for every profile loaded.  If a profile
+ * is replaced it receives the sid of the profile it is replacing.
+ *
+ * The sid value of 0 is invalid.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include "include/sid.h"
+
+/* global counter from which sids are allocated */
+static u32 global_sid;
+static DEFINE_SPINLOCK(sid_lock);
+
+/* TODO FIXME: add sid to profile mapping, and sid recycling */
+
+/**
+ * aa_alloc_sid - allocate a new sid for a profile
+ */
+u32 aa_alloc_sid(void)
+{
+       u32 sid;
+
+       /*
+        * TODO FIXME: sid recycling - part of profile mapping table
+        */
+       spin_lock(&sid_lock);
+       sid = (++global_sid);
+       spin_unlock(&sid_lock);
+       return sid;
+}
+
+/**
+ * aa_free_sid - free a sid
+ * @sid: sid to free
+ */
+void aa_free_sid(u32 sid)
+{
+       ;                       /* NOP ATM */
+}
index 8168e3ecd5bf9d43eb5b0c2b3e94636e992d7861..a0bbf30fb6dc93de4fe29da540be3533e797dede 100644 (file)
@@ -27,7 +27,7 @@ static int cap_quota_on(struct dentry *dentry)
        return 0;
 }
 
-static int cap_bprm_check_security (struct linux_binprm *bprm)
+static int cap_bprm_check_security(struct linux_binprm *bprm)
 {
        return 0;
 }
@@ -268,8 +268,7 @@ static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
        return 0;
 }
 
-static int cap_path_truncate(struct path *path, loff_t length,
-                            unsigned int time_attrs)
+static int cap_path_truncate(struct path *path)
 {
        return 0;
 }
index 1c812e874504ef90e1b8748e28d6d9e73d6a5912..8c777f022ad132eca07eed38503ea1af716f8dfd 100644 (file)
@@ -86,7 +86,7 @@ static int mknod(struct inode *dir, struct dentry *dentry,
                         int mode, dev_t dev)
 {
        struct inode *inode;
-       int error = -EPERM;
+       int error = -ENOMEM;
 
        if (dentry->d_inode)
                return -EEXIST;
@@ -166,6 +166,8 @@ static int create_by_name(const char *name, mode_t mode,
                        error = mkdir(parent->d_inode, *dentry, mode);
                else
                        error = create(parent->d_inode, *dentry, mode);
+               if (error)
+                       dput(*dentry);
        } else
                error = PTR_ERR(*dentry);
        mutex_unlock(&parent->d_inode->i_mutex);
index 8fe736aabe71264d3018f35a1a3c7d64806411bb..ef21b96a0b4231638c4d932747174bbda2b73309 100644 (file)
@@ -45,7 +45,8 @@ static ssize_t ima_show_htable_violations(struct file *filp,
 }
 
 static const struct file_operations ima_htable_violations_ops = {
-       .read = ima_show_htable_violations
+       .read = ima_show_htable_violations,
+       .llseek = generic_file_llseek,
 };
 
 static ssize_t ima_show_measurements_count(struct file *filp,
@@ -57,7 +58,8 @@ static ssize_t ima_show_measurements_count(struct file *filp,
 }
 
 static const struct file_operations ima_measurements_count_ops = {
-       .read = ima_show_measurements_count
+       .read = ima_show_measurements_count,
+       .llseek = generic_file_llseek,
 };
 
 /* returns pointer to hlist_node */
@@ -319,7 +321,8 @@ static int ima_release_policy(struct inode *inode, struct file *file)
 static const struct file_operations ima_measure_policy_ops = {
        .open = ima_open_policy,
        .write = ima_write_policy,
-       .release = ima_release_policy
+       .release = ima_release_policy,
+       .llseek = generic_file_llseek,
 };
 
 int __init ima_fs_init(void)
index 38783dcf6c61fb6e380131c40c8abbbf1414a5dd..addb67b169f443f136e3baf28846710e82fd0ff1 100644 (file)
@@ -114,6 +114,10 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                                    const void *description,
                                    key_match_func_t match);
 
+extern key_ref_t search_my_process_keyrings(struct key_type *type,
+                                           const void *description,
+                                           key_match_func_t match,
+                                           const struct cred *cred);
 extern key_ref_t search_process_keyrings(struct key_type *type,
                                         const void *description,
                                         key_match_func_t match,
@@ -134,6 +138,7 @@ extern struct key *request_key_and_link(struct key_type *type,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
+extern int lookup_user_key_possessed(const struct key *key, const void *target);
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
                                 key_perm_t perm);
 #define KEY_LOOKUP_CREATE      0x01
index 6261745e44591acd65bb47e18e9f65b9e842bfe5..b2b0998d6abda7759433d7032d255eb0a317c126 100644 (file)
@@ -505,13 +505,11 @@ okay:
 
        ret = snprintf(tmpbuf, PAGE_SIZE - 1,
                       "%s;%d;%d;%08x;%s",
-                      key_ref_to_ptr(key_ref)->type->name,
-                      key_ref_to_ptr(key_ref)->uid,
-                      key_ref_to_ptr(key_ref)->gid,
-                      key_ref_to_ptr(key_ref)->perm,
-                      key_ref_to_ptr(key_ref)->description ?
-                      key_ref_to_ptr(key_ref)->description : ""
-                      );
+                      key->type->name,
+                      key->uid,
+                      key->gid,
+                      key->perm,
+                      key->description ?: "");
 
        /* include a NUL char at the end of the data */
        if (ret > PAGE_SIZE - 1)
@@ -1091,7 +1089,7 @@ error:
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 {
        struct timespec now;
-       struct key *key;
+       struct key *key, *instkey;
        key_ref_t key_ref;
        time_t expiry;
        long ret;
@@ -1099,10 +1097,25 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
        key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
                                  KEY_SETATTR);
        if (IS_ERR(key_ref)) {
+               /* setting the timeout on a key under construction is permitted
+                * if we have the authorisation token handy */
+               if (PTR_ERR(key_ref) == -EACCES) {
+                       instkey = key_get_instantiation_authkey(id);
+                       if (!IS_ERR(instkey)) {
+                               key_put(instkey);
+                               key_ref = lookup_user_key(id,
+                                                         KEY_LOOKUP_PARTIAL,
+                                                         0);
+                               if (!IS_ERR(key_ref))
+                                       goto okay;
+                       }
+               }
+
                ret = PTR_ERR(key_ref);
                goto error;
        }
 
+okay:
        key = key_ref_to_ptr(key_ref);
 
        /* make the changes with the locks held to prevent races */
index 068b66ea2f1bbf17dd2c9062530b9d1c64e19612..70373966816e9845594919d870fca1f3e441ca65 100644 (file)
@@ -184,20 +184,36 @@ static void proc_keys_stop(struct seq_file *p, void *v)
 
 static int proc_keys_show(struct seq_file *m, void *v)
 {
+       const struct cred *cred = current_cred();
        struct rb_node *_p = v;
        struct key *key = rb_entry(_p, struct key, serial_node);
        struct timespec now;
        unsigned long timo;
+       key_ref_t key_ref, skey_ref;
        char xbuf[12];
        int rc;
 
+       key_ref = make_key_ref(key, 0);
+
+       /* determine if the key is possessed by this process (a test we can
+        * skip if the key does not indicate the possessor can view it
+        */
+       if (key->perm & KEY_POS_VIEW) {
+               skey_ref = search_my_process_keyrings(key->type, key,
+                                                     lookup_user_key_possessed,
+                                                     cred);
+               if (!IS_ERR(skey_ref)) {
+                       key_ref_put(skey_ref);
+                       key_ref = make_key_ref(key, 1);
+               }
+       }
+
        /* check whether the current task is allowed to view the key (assuming
         * non-possession)
         * - the caller holds a spinlock, and thus the RCU read lock, making our
         *   access to __current_cred() safe
         */
-       rc = key_task_permission(make_key_ref(key, 0), current_cred(),
-                                KEY_VIEW);
+       rc = key_task_permission(key_ref, cred, KEY_VIEW);
        if (rc < 0)
                return 0;
 
index 6b8e4ff4cc68cfebe2bb845dda44d8d4b8542635..f8e7251ae2c8f081ed25bf9920fa8aa33c8f287a 100644 (file)
@@ -309,22 +309,19 @@ void key_fsgid_changed(struct task_struct *tsk)
 
 /*****************************************************************************/
 /*
- * search the process keyrings for the first matching key
+ * search only my process keyrings for the first matching key
  * - we use the supplied match function to see if the description (or other
  *   feature of interest) matches
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-key_ref_t search_process_keyrings(struct key_type *type,
-                                 const void *description,
-                                 key_match_func_t match,
-                                 const struct cred *cred)
+key_ref_t search_my_process_keyrings(struct key_type *type,
+                                    const void *description,
+                                    key_match_func_t match,
+                                    const struct cred *cred)
 {
-       struct request_key_auth *rka;
        key_ref_t key_ref, ret, err;
 
-       might_sleep();
-
        /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
         * searchable, but we failed to find a key or we found a negative key;
         * otherwise we want to return a sample error (probably -EACCES) if
@@ -424,6 +421,36 @@ key_ref_t search_process_keyrings(struct key_type *type,
                }
        }
 
+       /* no key - decide on the error we're going to go for */
+       key_ref = ret ? ret : err;
+
+found:
+       return key_ref;
+}
+
+/*****************************************************************************/
+/*
+ * search the process keyrings for the first matching key
+ * - we use the supplied match function to see if the description (or other
+ *   feature of interest) matches
+ * - we return -EAGAIN if we didn't find any matching key
+ * - we return -ENOKEY if we found only negative matching keys
+ */
+key_ref_t search_process_keyrings(struct key_type *type,
+                                 const void *description,
+                                 key_match_func_t match,
+                                 const struct cred *cred)
+{
+       struct request_key_auth *rka;
+       key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
+
+       might_sleep();
+
+       key_ref = search_my_process_keyrings(type, description, match, cred);
+       if (!IS_ERR(key_ref))
+               goto found;
+       err = key_ref;
+
        /* if this process has an instantiation authorisation key, then we also
         * search the keyrings of the process mentioned there
         * - we don't permit access to request_key auth keys via this method
@@ -446,24 +473,19 @@ key_ref_t search_process_keyrings(struct key_type *type,
                        if (!IS_ERR(key_ref))
                                goto found;
 
-                       switch (PTR_ERR(key_ref)) {
-                       case -EAGAIN: /* no key */
-                               if (ret)
-                                       break;
-                       case -ENOKEY: /* negative key */
-                               ret = key_ref;
-                               break;
-                       default:
-                               err = key_ref;
-                               break;
-                       }
+                       ret = key_ref;
                } else {
                        up_read(&cred->request_key_auth->sem);
                }
        }
 
        /* no key - decide on the error we're going to go for */
-       key_ref = ret ? ret : err;
+       if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
+               key_ref = ERR_PTR(-ENOKEY);
+       else if (err == ERR_PTR(-EACCES))
+               key_ref = ret;
+       else
+               key_ref = err;
 
 found:
        return key_ref;
@@ -474,7 +496,7 @@ found:
 /*
  * see if the key we're looking at is the target key
  */
-static int lookup_user_key_possessed(const struct key *key, const void *target)
+int lookup_user_key_possessed(const struct key *key, const void *target)
 {
        return key == target;
 
index f5ec9ac5d57cf6af80f90eb90427ecb98385ae4f..0d26f689bd7726f7d253607a0f5899c00e947fcc 100644 (file)
@@ -144,6 +144,7 @@ static int call_sbin_request_key(struct key_construction *cons,
        prkey = 0;
        if (cred->tgcred->process_keyring)
                prkey = cred->tgcred->process_keyring->serial;
+       sprintf(keyring_str[1], "%d", prkey);
 
        rcu_read_lock();
        session = rcu_dereference(cred->tgcred->session_keyring);
index 351942a4ca0e79b0c21ccd35c31e442928792f47..e8c87b8601b4560bda565064212b79d0004d46ed 100644 (file)
@@ -417,12 +417,11 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
                                         new_dentry);
 }
 
-int security_path_truncate(struct path *path, loff_t length,
-                          unsigned int time_attrs)
+int security_path_truncate(struct path *path)
 {
        if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
                return 0;
-       return security_ops->path_truncate(path, length, time_attrs);
+       return security_ops->path_truncate(path);
 }
 
 int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
index 7f1a304712a9690e419e575d816e4d14e697b0b7..9da6420e2056541f330d85e41be66f4742691e2b 100644 (file)
@@ -288,7 +288,6 @@ static struct avc_node *avc_alloc_node(void)
        if (!node)
                goto out;
 
-       INIT_RCU_HEAD(&node->rhead);
        INIT_HLIST_NODE(&node->list);
        avc_cache_stats_incr(allocations);
 
@@ -489,9 +488,29 @@ void avc_audit(u32 ssid, u32 tsid,
        struct common_audit_data stack_data;
        u32 denied, audited;
        denied = requested & ~avd->allowed;
-       if (denied)
+       if (denied) {
                audited = denied & avd->auditdeny;
-       else if (result)
+               /*
+                * a->selinux_audit_data.auditdeny is TRICKY!  Setting a bit in
+                * this field means that ANY denials should NOT be audited if
+                * the policy contains an explicit dontaudit rule for that
+                * permission.  Take notice that this is unrelated to the
+                * actual permissions that were denied.  As an example lets
+                * assume:
+                *
+                * denied == READ
+                * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
+                * selinux_audit_data.auditdeny & ACCESS == 1
+                *
+                * We will NOT audit the denial even though the denied
+                * permission was READ and the auditdeny checks were for
+                * ACCESS
+                */
+               if (a &&
+                   a->selinux_audit_data.auditdeny &&
+                   !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+                       audited = 0;
+       } else if (result)
                audited = denied = requested;
        else
                audited = requested & avd->auditallow;
index 5c9f25ba1c9537faa8e1ea91a482dd8960cb745e..9b40f4c0ac7032e3d80d2508ba96024fd28d2512 100644 (file)
@@ -87,9 +87,6 @@
 #include "netlabel.h"
 #include "audit.h"
 
-#define XATTR_SELINUX_SUFFIX "selinux"
-#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
-
 #define NUM_SEL_MNT_OPTS 5
 
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -188,7 +185,7 @@ static inline u32 task_sid(const struct task_struct *task)
  */
 static inline u32 current_sid(void)
 {
-       const struct task_security_struct *tsec = current_cred()->security;
+       const struct task_security_struct *tsec = current_security();
 
        return tsec->sid;
 }
@@ -279,32 +276,6 @@ static void superblock_free_security(struct super_block *sb)
        kfree(sbsec);
 }
 
-static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
-{
-       struct sk_security_struct *sksec;
-
-       sksec = kzalloc(sizeof(*sksec), priority);
-       if (!sksec)
-               return -ENOMEM;
-
-       sksec->peer_sid = SECINITSID_UNLABELED;
-       sksec->sid = SECINITSID_UNLABELED;
-       sk->sk_security = sksec;
-
-       selinux_netlbl_sk_security_reset(sksec);
-
-       return 0;
-}
-
-static void sk_free_security(struct sock *sk)
-{
-       struct sk_security_struct *sksec = sk->sk_security;
-
-       sk->sk_security = NULL;
-       selinux_netlbl_sk_security_free(sksec);
-       kfree(sksec);
-}
-
 /* The security server must be initialized before
    any labeling or access decisions can be provided. */
 extern int ss_initialized;
@@ -1584,8 +1555,7 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
@@ -1806,27 +1776,9 @@ static inline u32 open_file_to_av(struct file *file)
 {
        u32 av = file_to_av(file);
 
-       if (selinux_policycap_openperm) {
-               mode_t mode = file->f_path.dentry->d_inode->i_mode;
-               /*
-                * lnk files and socks do not really have an 'open'
-                */
-               if (S_ISREG(mode))
-                       av |= FILE__OPEN;
-               else if (S_ISCHR(mode))
-                       av |= CHR_FILE__OPEN;
-               else if (S_ISBLK(mode))
-                       av |= BLK_FILE__OPEN;
-               else if (S_ISFIFO(mode))
-                       av |= FIFO_FILE__OPEN;
-               else if (S_ISDIR(mode))
-                       av |= DIR__OPEN;
-               else if (S_ISSOCK(mode))
-                       av |= SOCK_FILE__OPEN;
-               else
-                       printk(KERN_ERR "SELinux: WARNING: inside %s with "
-                               "unknown mode:%o\n", __func__, mode);
-       }
+       if (selinux_policycap_openperm)
+               av |= FILE__OPEN;
+
        return av;
 }
 
@@ -2183,8 +2135,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
 
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        u32 sid, osid;
        int atsecure = 0;
 
@@ -2559,8 +2510,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       char **name, void **value,
                                       size_t *len)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid, clen;
@@ -2676,14 +2626,26 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
        const struct cred *cred = current_cred();
+       struct common_audit_data ad;
+       u32 perms;
+       bool from_access;
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
+       from_access = mask & MAY_ACCESS;
+       mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
+
+       /* No permission to check.  Existence test. */
+       if (!mask)
                return 0;
-       }
 
-       return inode_has_perm(cred, inode,
-                             file_mask_to_av(inode->i_mode, mask), NULL);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       ad.u.fs.inode = inode;
+
+       if (from_access)
+               ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+
+       perms = file_mask_to_av(inode->i_mode, mask);
+
+       return inode_has_perm(cred, inode, perms, &ad);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -3671,71 +3633,54 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
 }
 
 /* socket security operations */
-static int socket_has_perm(struct task_struct *task, struct socket *sock,
-                          u32 perms)
+
+static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
 {
-       struct inode_security_struct *isec;
-       struct common_audit_data ad;
-       u32 sid;
-       int err = 0;
+       return tsec->sockcreate_sid ? : tsec->sid;
+}
 
-       isec = SOCK_INODE(sock)->i_security;
+static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct common_audit_data ad;
+       u32 tsid = task_sid(task);
 
-       if (isec->sid == SECINITSID_KERNEL)
-               goto out;
-       sid = task_sid(task);
+       if (sksec->sid == SECINITSID_KERNEL)
+               return 0;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.sk = sock->sk;
-       err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+       ad.u.net.sk = sk;
 
-out:
-       return err;
+       return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
 }
 
 static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
-       u32 sid, newsid;
+       const struct task_security_struct *tsec = current_security();
+       u32 newsid;
        u16 secclass;
-       int err = 0;
 
        if (kern)
-               goto out;
-
-       sid = tsec->sid;
-       newsid = tsec->sockcreate_sid ?: sid;
+               return 0;
 
+       newsid = socket_sockcreate_sid(tsec);
        secclass = socket_type_to_security_class(family, type, protocol);
-       err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
-
-out:
-       return err;
+       return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
 }
 
 static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
-       struct inode_security_struct *isec;
+       const struct task_security_struct *tsec = current_security();
+       struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
        struct sk_security_struct *sksec;
-       u32 sid, newsid;
        int err = 0;
 
-       sid = tsec->sid;
-       newsid = tsec->sockcreate_sid;
-
-       isec = SOCK_INODE(sock)->i_security;
-
        if (kern)
                isec->sid = SECINITSID_KERNEL;
-       else if (newsid)
-               isec->sid = newsid;
        else
-               isec->sid = sid;
+               isec->sid = socket_sockcreate_sid(tsec);
 
        isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->initialized = 1;
@@ -3756,10 +3701,11 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 
 static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+       struct sock *sk = sock->sk;
        u16 family;
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__BIND);
+       err = sock_has_perm(current, sk, SOCKET__BIND);
        if (err)
                goto out;
 
@@ -3768,19 +3714,16 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
         * Multiple address binding for SCTP is not supported yet: we just
         * check the first address now.
         */
-       family = sock->sk->sk_family;
+       family = sk->sk_family;
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
-               struct inode_security_struct *isec;
+               struct sk_security_struct *sksec = sk->sk_security;
                struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
-               struct sock *sk = sock->sk;
                u32 sid, node_perm;
 
-               isec = SOCK_INODE(sock)->i_security;
-
                if (family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
                        snum = ntohs(addr4->sin_port);
@@ -3804,15 +3747,15 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                COMMON_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
-                               err = avc_has_perm(isec->sid, sid,
-                                                  isec->sclass,
+                               err = avc_has_perm(sksec->sid, sid,
+                                                  sksec->sclass,
                                                   SOCKET__NAME_BIND, &ad);
                                if (err)
                                        goto out;
                        }
                }
 
-               switch (isec->sclass) {
+               switch (sksec->sclass) {
                case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
@@ -3843,8 +3786,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                else
                        ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
 
-               err = avc_has_perm(isec->sid, sid,
-                                  isec->sclass, node_perm, &ad);
+               err = avc_has_perm(sksec->sid, sid,
+                                  sksec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
@@ -3855,19 +3798,18 @@ out:
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
        struct sock *sk = sock->sk;
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sk->sk_security;
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__CONNECT);
+       err = sock_has_perm(current, sk, SOCKET__CONNECT);
        if (err)
                return err;
 
        /*
         * If a TCP or DCCP socket, check name_connect permission for the port.
         */
-       isec = SOCK_INODE(sock)->i_security;
-       if (isec->sclass == SECCLASS_TCP_SOCKET ||
-           isec->sclass == SECCLASS_DCCP_SOCKET) {
+       if (sksec->sclass == SECCLASS_TCP_SOCKET ||
+           sksec->sclass == SECCLASS_DCCP_SOCKET) {
                struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
@@ -3890,13 +3832,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                if (err)
                        goto out;
 
-               perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
+               perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
                COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
-               err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
+               err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
                if (err)
                        goto out;
        }
@@ -3909,7 +3851,7 @@ out:
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
 {
-       return socket_has_perm(current, sock, SOCKET__LISTEN);
+       return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
 }
 
 static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
@@ -3918,7 +3860,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        struct inode_security_struct *isec;
        struct inode_security_struct *newisec;
 
-       err = socket_has_perm(current, sock, SOCKET__ACCEPT);
+       err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
        if (err)
                return err;
 
@@ -3935,30 +3877,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
 {
-       return socket_has_perm(current, sock, SOCKET__WRITE);
+       return sock_has_perm(current, sock->sk, SOCKET__WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
                                  int size, int flags)
 {
-       return socket_has_perm(current, sock, SOCKET__READ);
+       return sock_has_perm(current, sock->sk, SOCKET__READ);
 }
 
 static int selinux_socket_getsockname(struct socket *sock)
 {
-       return socket_has_perm(current, sock, SOCKET__GETATTR);
+       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_getpeername(struct socket *sock)
 {
-       return socket_has_perm(current, sock, SOCKET__GETATTR);
+       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__SETOPT);
+       err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
        if (err)
                return err;
 
@@ -3968,68 +3910,58 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname
 static int selinux_socket_getsockopt(struct socket *sock, int level,
                                     int optname)
 {
-       return socket_has_perm(current, sock, SOCKET__GETOPT);
+       return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
 }
 
 static int selinux_socket_shutdown(struct socket *sock, int how)
 {
-       return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
+       return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
 }
 
 static int selinux_socket_unix_stream_connect(struct socket *sock,
                                              struct socket *other,
                                              struct sock *newsk)
 {
-       struct sk_security_struct *sksec;
-       struct inode_security_struct *isec;
-       struct inode_security_struct *other_isec;
+       struct sk_security_struct *sksec_sock = sock->sk->sk_security;
+       struct sk_security_struct *sksec_other = other->sk->sk_security;
+       struct sk_security_struct *sksec_new = newsk->sk_security;
        struct common_audit_data ad;
        int err;
 
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
-
        COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
-       err = avc_has_perm(isec->sid, other_isec->sid,
-                          isec->sclass,
+       err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
+                          sksec_other->sclass,
                           UNIX_STREAM_SOCKET__CONNECTTO, &ad);
        if (err)
                return err;
 
-       /* connecting socket */
-       sksec = sock->sk->sk_security;
-       sksec->peer_sid = other_isec->sid;
-
        /* server child socket */
-       sksec = newsk->sk_security;
-       sksec->peer_sid = isec->sid;
-       err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid);
+       sksec_new->peer_sid = sksec_sock->sid;
+       err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
+                                   &sksec_new->sid);
+       if (err)
+               return err;
 
-       return err;
+       /* connecting socket */
+       sksec_sock->peer_sid = sksec_new->sid;
+
+       return 0;
 }
 
 static int selinux_socket_unix_may_send(struct socket *sock,
                                        struct socket *other)
 {
-       struct inode_security_struct *isec;
-       struct inode_security_struct *other_isec;
+       struct sk_security_struct *ssec = sock->sk->sk_security;
+       struct sk_security_struct *osec = other->sk->sk_security;
        struct common_audit_data ad;
-       int err;
-
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
-       err = avc_has_perm(isec->sid, other_isec->sid,
-                          isec->sclass, SOCKET__SENDTO, &ad);
-       if (err)
-               return err;
-
-       return 0;
+       return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+                           &ad);
 }
 
 static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
@@ -4168,26 +4100,18 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
        int err = 0;
        char *scontext;
        u32 scontext_len;
-       struct sk_security_struct *sksec;
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sock->sk->sk_security;
        u32 peer_sid = SECSID_NULL;
 
-       isec = SOCK_INODE(sock)->i_security;
-
-       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
-           isec->sclass == SECCLASS_TCP_SOCKET) {
-               sksec = sock->sk->sk_security;
+       if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+           sksec->sclass == SECCLASS_TCP_SOCKET)
                peer_sid = sksec->peer_sid;
-       }
-       if (peer_sid == SECSID_NULL) {
-               err = -ENOPROTOOPT;
-               goto out;
-       }
+       if (peer_sid == SECSID_NULL)
+               return -ENOPROTOOPT;
 
        err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
        if (err)
-               goto out;
+               return err;
 
        if (scontext_len > len) {
                err = -ERANGE;
@@ -4200,9 +4124,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
 out_len:
        if (put_user(scontext_len, optlen))
                err = -EFAULT;
-
        kfree(scontext);
-out:
        return err;
 }
 
@@ -4234,12 +4156,27 @@ out:
 
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
-       return sk_alloc_security(sk, family, priority);
+       struct sk_security_struct *sksec;
+
+       sksec = kzalloc(sizeof(*sksec), priority);
+       if (!sksec)
+               return -ENOMEM;
+
+       sksec->peer_sid = SECINITSID_UNLABELED;
+       sksec->sid = SECINITSID_UNLABELED;
+       selinux_netlbl_sk_security_reset(sksec);
+       sk->sk_security = sksec;
+
+       return 0;
 }
 
 static void selinux_sk_free_security(struct sock *sk)
 {
-       sk_free_security(sk);
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       sk->sk_security = NULL;
+       selinux_netlbl_sk_security_free(sksec);
+       kfree(sksec);
 }
 
 static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
@@ -4399,8 +4336,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        int err = 0;
        u32 perm;
        struct nlmsghdr *nlh;
-       struct socket *sock = sk->sk_socket;
-       struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+       struct sk_security_struct *sksec = sk->sk_security;
 
        if (skb->len < NLMSG_SPACE(0)) {
                err = -EINVAL;
@@ -4408,13 +4344,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        }
        nlh = nlmsg_hdr(skb);
 
-       err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+       err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
                        audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
                                  "SELinux:  unrecognized netlink message"
                                  " type=%hu for sclass=%hu\n",
-                                 nlh->nlmsg_type, isec->sclass);
+                                 nlh->nlmsg_type, sksec->sclass);
                        if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
@@ -4425,7 +4361,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
                goto out;
        }
 
-       err = socket_has_perm(current, sock, perm);
+       err = sock_has_perm(current, sk, perm);
 out:
        return err;
 }
index 8b32e959bb2e47cc559e29aaf7468576d63974a5..b4c9eb4bd6f9127a506e2a4483c592362c8fcafa 100644 (file)
@@ -2,7 +2,8 @@
     "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
 
 #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
-    "rename", "execute", "swapon", "quotaon", "mounton"
+    "rename", "execute", "swapon", "quotaon", "mounton", "audit_access", \
+    "open", "execmod"
 
 #define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
     "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom",  \
@@ -43,22 +44,21 @@ struct security_class_mapping secclass_map[] = {
            "quotaget", NULL } },
        { "file",
          { COMMON_FILE_PERMS,
-           "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+           "execute_no_trans", "entrypoint", NULL } },
        { "dir",
          { COMMON_FILE_PERMS, "add_name", "remove_name",
-           "reparent", "search", "rmdir", "open", NULL } },
+           "reparent", "search", "rmdir", NULL } },
        { "fd", { "use", NULL } },
        { "lnk_file",
          { COMMON_FILE_PERMS, NULL } },
        { "chr_file",
-         { COMMON_FILE_PERMS,
-           "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+         { COMMON_FILE_PERMS, NULL } },
        { "blk_file",
-         { COMMON_FILE_PERMS, "open", NULL } },
+         { COMMON_FILE_PERMS, NULL } },
        { "sock_file",
-         { COMMON_FILE_PERMS, "open", NULL } },
+         { COMMON_FILE_PERMS, NULL } },
        { "fifo_file",
-         { COMMON_FILE_PERMS, "open", NULL } },
+         { COMMON_FILE_PERMS, NULL } },
        { "socket",
          { COMMON_SOCK_PERMS, NULL } },
        { "tcp_socket",
index dc92792271f1d8e59e01e9f4e9000d4f0090b2c0..65ebfe954f85395f490ce74d694d73a859b523ac 100644 (file)
@@ -183,8 +183,6 @@ static void sel_netnode_insert(struct sel_netnode *node)
                BUG();
        }
 
-       INIT_RCU_HEAD(&node->rcu);
-
        /* we need to impose a limit on the growth of the hash table so check
         * this bucket to make sure it is within the specified bounds */
        list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
index 0293843f7eda7d41e7722bd55e41bbc5ea0110a3..79a1bb635662fbc7f65a306e10b5b67e534fcf1c 100644 (file)
@@ -184,6 +184,7 @@ out:
 static const struct file_operations sel_enforce_ops = {
        .read           = sel_read_enforce,
        .write          = sel_write_enforce,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
@@ -201,6 +202,7 @@ static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
 
 static const struct file_operations sel_handle_unknown_ops = {
        .read           = sel_read_handle_unknown,
+       .llseek         = generic_file_llseek,
 };
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
@@ -251,6 +253,7 @@ out:
 
 static const struct file_operations sel_disable_ops = {
        .write          = sel_write_disable,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
@@ -265,6 +268,7 @@ static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
 
 static const struct file_operations sel_policyvers_ops = {
        .read           = sel_read_policyvers,
+       .llseek         = generic_file_llseek,
 };
 
 /* declaration for sel_write_load */
@@ -289,6 +293,7 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
 
 static const struct file_operations sel_mls_ops = {
        .read           = sel_read_mls,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_write_load(struct file *file, const char __user *buf,
@@ -356,6 +361,7 @@ out:
 
 static const struct file_operations sel_load_ops = {
        .write          = sel_write_load,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
@@ -437,6 +443,7 @@ out:
 static const struct file_operations sel_checkreqprot_ops = {
        .read           = sel_read_checkreqprot,
        .write          = sel_write_checkreqprot,
+       .llseek         = generic_file_llseek,
 };
 
 /*
@@ -482,6 +489,7 @@ static const struct file_operations transaction_ops = {
        .write          = selinux_transaction_write,
        .read           = simple_transaction_read,
        .release        = simple_transaction_release,
+       .llseek         = generic_file_llseek,
 };
 
 /*
@@ -883,6 +891,7 @@ out:
 static const struct file_operations sel_bool_ops = {
        .read           = sel_read_bool,
        .write          = sel_write_bool,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_commit_bools_write(struct file *filep,
@@ -935,6 +944,7 @@ out:
 
 static const struct file_operations sel_commit_bools_ops = {
        .write          = sel_commit_bools_write,
+       .llseek         = generic_file_llseek,
 };
 
 static void sel_remove_entries(struct dentry *de)
@@ -1127,10 +1137,12 @@ out:
 static const struct file_operations sel_avc_cache_threshold_ops = {
        .read           = sel_read_avc_cache_threshold,
        .write          = sel_write_avc_cache_threshold,
+       .llseek         = generic_file_llseek,
 };
 
 static const struct file_operations sel_avc_hash_stats_ops = {
        .read           = sel_read_avc_hash_stats,
+       .llseek         = generic_file_llseek,
 };
 
 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
@@ -1255,6 +1267,7 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
 
 static const struct file_operations sel_initcon_ops = {
        .read           = sel_read_initcon,
+       .llseek         = generic_file_llseek,
 };
 
 static int sel_make_initcon_files(struct dentry *dir)
@@ -1330,6 +1343,7 @@ out:
 
 static const struct file_operations sel_class_ops = {
        .read           = sel_read_class,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_read_perm(struct file *file, char __user *buf,
@@ -1354,6 +1368,7 @@ out:
 
 static const struct file_operations sel_perm_ops = {
        .read           = sel_read_perm,
+       .llseek         = generic_file_llseek,
 };
 
 static ssize_t sel_read_policycap(struct file *file, char __user *buf,
@@ -1372,6 +1387,7 @@ static ssize_t sel_read_policycap(struct file *file, char __user *buf,
 
 static const struct file_operations sel_policycap_ops = {
        .read           = sel_read_policycap,
+       .llseek         = generic_file_llseek,
 };
 
 static int sel_make_perm_files(char *objclass, int classvalue,
index 1215b8e47dba669a6d86519b342de621b2efbfd2..929480c6c4306e874eff82db107045b944cdd33b 100644 (file)
@@ -342,20 +342,20 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
 
        if (vers < POLICYDB_VERSION_AVTAB) {
                rc = next_entry(buf32, fp, sizeof(u32));
-               if (rc < 0) {
+               if (rc) {
                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-                       return -1;
+                       return rc;
                }
                items2 = le32_to_cpu(buf32[0]);
                if (items2 > ARRAY_SIZE(buf32)) {
                        printk(KERN_ERR "SELinux: avtab: entry overflow\n");
-                       return -1;
+                       return -EINVAL;
 
                }
                rc = next_entry(buf32, fp, sizeof(u32)*items2);
-               if (rc < 0) {
+               if (rc) {
                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-                       return -1;
+                       return rc;
                }
                items = 0;
 
@@ -363,19 +363,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
                key.source_type = (u16)val;
                if (key.source_type != val) {
                        printk(KERN_ERR "SELinux: avtab: truncated source type\n");
-                       return -1;
+                       return -EINVAL;
                }
                val = le32_to_cpu(buf32[items++]);
                key.target_type = (u16)val;
                if (key.target_type != val) {
                        printk(KERN_ERR "SELinux: avtab: truncated target type\n");
-                       return -1;
+                       return -EINVAL;
                }
                val = le32_to_cpu(buf32[items++]);
                key.target_class = (u16)val;
                if (key.target_class != val) {
                        printk(KERN_ERR "SELinux: avtab: truncated target class\n");
-                       return -1;
+                       return -EINVAL;
                }
 
                val = le32_to_cpu(buf32[items++]);
@@ -383,12 +383,12 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
 
                if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
                        printk(KERN_ERR "SELinux: avtab: null entry\n");
-                       return -1;
+                       return -EINVAL;
                }
                if ((val & AVTAB_AV) &&
                    (val & AVTAB_TYPE)) {
                        printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
-                       return -1;
+                       return -EINVAL;
                }
 
                for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
@@ -403,15 +403,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
 
                if (items != items2) {
                        printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
-                       return -1;
+                       return -EINVAL;
                }
                return 0;
        }
 
        rc = next_entry(buf16, fp, sizeof(u16)*4);
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-               return -1;
+               return rc;
        }
 
        items = 0;
@@ -424,7 +424,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
            !policydb_type_isvalid(pol, key.target_type) ||
            !policydb_class_isvalid(pol, key.target_class)) {
                printk(KERN_ERR "SELinux: avtab: invalid type or class\n");
-               return -1;
+               return -EINVAL;
        }
 
        set = 0;
@@ -434,19 +434,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
        }
        if (!set || set > 1) {
                printk(KERN_ERR "SELinux:  avtab:  more than one specifier\n");
-               return -1;
+               return -EINVAL;
        }
 
        rc = next_entry(buf32, fp, sizeof(u32));
-       if (rc < 0) {
+       if (rc) {
                printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-               return -1;
+               return rc;
        }
        datum.data = le32_to_cpu(*buf32);
        if ((key.specified & AVTAB_TYPE) &&
            !policydb_type_isvalid(pol, datum.data)) {
                printk(KERN_ERR "SELinux: avtab: invalid type\n");
-               return -1;
+               return -EINVAL;
        }
        return insertf(a, &key, &datum, p);
 }
@@ -487,8 +487,7 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
                                printk(KERN_ERR "SELinux: avtab: out of memory\n");
                        else if (rc == -EEXIST)
                                printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
-                       else
-                               rc = -EINVAL;
+
                        goto bad;
                }
        }
index 4a4e35cac22bfc2a7426dd85e582ce113e07e843..c91e150c3087d78127eb8ca6cc6faccf04e9cd32 100644 (file)
@@ -117,10 +117,14 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node)
 
 int cond_policydb_init(struct policydb *p)
 {
+       int rc;
+
        p->bool_val_to_struct = NULL;
        p->cond_list = NULL;
-       if (avtab_init(&p->te_cond_avtab))
-               return -1;
+
+       rc = avtab_init(&p->te_cond_avtab);
+       if (rc)
+               return rc;
 
        return 0;
 }
@@ -219,34 +223,37 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
 
        booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
        if (!booldatum)
-               return -1;
+               return -ENOMEM;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
+       if (rc)
                goto err;
 
        booldatum->value = le32_to_cpu(buf[0]);
        booldatum->state = le32_to_cpu(buf[1]);
 
+       rc = -EINVAL;
        if (!bool_isvalid(booldatum))
                goto err;
 
        len = le32_to_cpu(buf[2]);
 
+       rc = -ENOMEM;
        key = kmalloc(len + 1, GFP_KERNEL);
        if (!key)
                goto err;
        rc = next_entry(key, fp, len);
-       if (rc < 0)
+       if (rc)
                goto err;
        key[len] = '\0';
-       if (hashtab_insert(h, key, booldatum))
+       rc = hashtab_insert(h, key, booldatum);
+       if (rc)
                goto err;
 
        return 0;
 err:
        cond_destroy_bool(key, booldatum, NULL);
-       return -1;
+       return rc;
 }
 
 struct cond_insertf_data {
@@ -263,7 +270,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
        struct cond_av_list *other = data->other, *list, *cur;
        struct avtab_node *node_ptr;
        u8 found;
-
+       int rc = -EINVAL;
 
        /*
         * For type rules we have to make certain there aren't any
@@ -313,12 +320,15 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
        node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
        if (!node_ptr) {
                printk(KERN_ERR "SELinux: could not insert rule.\n");
+               rc = -ENOMEM;
                goto err;
        }
 
        list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
-       if (!list)
+       if (!list) {
+               rc = -ENOMEM;
                goto err;
+       }
 
        list->node = node_ptr;
        if (!data->head)
@@ -331,7 +341,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
 err:
        cond_av_list_destroy(data->head);
        data->head = NULL;
-       return -1;
+       return rc;
 }
 
 static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
@@ -345,8 +355,8 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
 
        len = 0;
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
-               return -1;
+       if (rc)
+               return rc;
 
        len = le32_to_cpu(buf[0]);
        if (len == 0)
@@ -361,7 +371,6 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
                                     &data);
                if (rc)
                        return rc;
-
        }
 
        *ret_list = data.head;
@@ -390,24 +399,25 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
        struct cond_expr *expr = NULL, *last = NULL;
 
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
-               return -1;
+       if (rc)
+               return rc;
 
        node->cur_state = le32_to_cpu(buf[0]);
 
        len = 0;
        rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
-               return -1;
+       if (rc)
+               return rc;
 
        /* expr */
        len = le32_to_cpu(buf[0]);
 
        for (i = 0; i < len; i++) {
                rc = next_entry(buf, fp, sizeof(u32) * 2);
-               if (rc < 0)
+               if (rc)
                        goto err;
 
+               rc = -ENOMEM;
                expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
                if (!expr)
                        goto err;
@@ -416,6 +426,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
                expr->bool = le32_to_cpu(buf[1]);
 
                if (!expr_isvalid(p, expr)) {
+                       rc = -EINVAL;
                        kfree(expr);
                        goto err;
                }
@@ -427,14 +438,16 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
                last = expr;
        }
 
-       if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+       rc = cond_read_av_list(p, fp, &node->true_list, NULL);
+       if (rc)
                goto err;
-       if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
+       rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
+       if (rc)
                goto err;
        return 0;
 err:
        cond_node_destroy(node);
-       return -1;
+       return rc;
 }
 
 int cond_read_list(struct policydb *p, void *fp)
@@ -445,8 +458,8 @@ int cond_read_list(struct policydb *p, void *fp)
        int rc;
 
        rc = next_entry(buf, fp, sizeof buf);
-       if (rc < 0)
-               return -1;
+       if (rc)
+               return rc;
 
        len = le32_to_cpu(buf[0]);
 
@@ -455,11 +468,13 @@ int cond_read_list(struct policydb *p, void *fp)
                goto err;
 
        for (i = 0; i < len; i++) {
+               rc = -ENOMEM;
                node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
                if (!node)
                        goto err;
 
-               if (cond_read_node(p, node, fp) != 0)
+               rc = cond_read_node(p, node, fp);
+               if (rc)
                        goto err;
 
                if (i == 0)
@@ -472,7 +487,7 @@ int cond_read_list(struct policydb *p, void *fp)
 err:
        cond_list_destroy(p->cond_list);
        p->cond_list = NULL;
-       return -1;
+       return rc;
 }
 
 /* Determine whether additional permissions are granted by the conditional
index c57802a164d5d3b840a287a06a15e58793610c4a..3a29704be8ce10f4409dd0a3d4f0bea8bb0d1086 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/audit.h>
+#include <linux/flex_array.h>
 #include "security.h"
 
 #include "policydb.h"
@@ -655,6 +656,9 @@ static int range_tr_destroy(void *key, void *datum, void *p)
 
 static void ocontext_destroy(struct ocontext *c, int i)
 {
+       if (!c)
+               return;
+
        context_destroy(&c->context[0]);
        context_destroy(&c->context[1]);
        if (i == OCON_ISID || i == OCON_FS ||
@@ -736,11 +740,17 @@ void policydb_destroy(struct policydb *p)
        hashtab_map(p->range_tr, range_tr_destroy, NULL);
        hashtab_destroy(p->range_tr);
 
-       if (p->type_attr_map) {
-               for (i = 0; i < p->p_types.nprim; i++)
-                       ebitmap_destroy(&p->type_attr_map[i]);
+       if (p->type_attr_map_array) {
+               for (i = 0; i < p->p_types.nprim; i++) {
+                       struct ebitmap *e;
+
+                       e = flex_array_get(p->type_attr_map_array, i);
+                       if (!e)
+                               continue;
+                       ebitmap_destroy(e);
+               }
+               flex_array_free(p->type_attr_map_array);
        }
-       kfree(p->type_attr_map);
        ebitmap_destroy(&p->policycaps);
        ebitmap_destroy(&p->permissive_map);
 
@@ -1701,6 +1711,333 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
        return 1U << (perdatum->value-1);
 }
 
+static int range_read(struct policydb *p, void *fp)
+{
+       struct range_trans *rt = NULL;
+       struct mls_range *r = NULL;
+       int i, rc;
+       __le32 buf[2];
+       u32 nel;
+
+       if (p->policyvers < POLICYDB_VERSION_MLS)
+               return 0;
+
+       rc = next_entry(buf, fp, sizeof(u32));
+       if (rc)
+               goto out;
+
+       nel = le32_to_cpu(buf[0]);
+       for (i = 0; i < nel; i++) {
+               rc = -ENOMEM;
+               rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+               if (!rt)
+                       goto out;
+
+               rc = next_entry(buf, fp, (sizeof(u32) * 2));
+               if (rc)
+                       goto out;
+
+               rt->source_type = le32_to_cpu(buf[0]);
+               rt->target_type = le32_to_cpu(buf[1]);
+               if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+                       rc = next_entry(buf, fp, sizeof(u32));
+                       if (rc)
+                               goto out;
+                       rt->target_class = le32_to_cpu(buf[0]);
+               } else
+                       rt->target_class = p->process_class;
+
+               rc = -EINVAL;
+               if (!policydb_type_isvalid(p, rt->source_type) ||
+                   !policydb_type_isvalid(p, rt->target_type) ||
+                   !policydb_class_isvalid(p, rt->target_class))
+                       goto out;
+
+               rc = -ENOMEM;
+               r = kzalloc(sizeof(*r), GFP_KERNEL);
+               if (!r)
+                       goto out;
+
+               rc = mls_read_range_helper(r, fp);
+               if (rc)
+                       goto out;
+
+               rc = -EINVAL;
+               if (!mls_range_isvalid(p, r)) {
+                       printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
+                       goto out;
+               }
+
+               rc = hashtab_insert(p->range_tr, rt, r);
+               if (rc)
+                       goto out;
+
+               rt = NULL;
+               r = NULL;
+       }
+       rangetr_hash_eval(p->range_tr);
+       rc = 0;
+out:
+       kfree(rt);
+       kfree(r);
+       return rc;
+}
+
+static int genfs_read(struct policydb *p, void *fp)
+{
+       int i, j, rc;
+       u32 nel, nel2, len, len2;
+       __le32 buf[1];
+       struct ocontext *l, *c;
+       struct ocontext *newc = NULL;
+       struct genfs *genfs_p, *genfs;
+       struct genfs *newgenfs = NULL;
+
+       rc = next_entry(buf, fp, sizeof(u32));
+       if (rc)
+               goto out;
+       nel = le32_to_cpu(buf[0]);
+
+       for (i = 0; i < nel; i++) {
+               rc = next_entry(buf, fp, sizeof(u32));
+               if (rc)
+                       goto out;
+               len = le32_to_cpu(buf[0]);
+
+               rc = -ENOMEM;
+               newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+               if (!newgenfs)
+                       goto out;
+
+               rc = -ENOMEM;
+               newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
+               if (!newgenfs->fstype)
+                       goto out;
+
+               rc = next_entry(newgenfs->fstype, fp, len);
+               if (rc)
+                       goto out;
+
+               newgenfs->fstype[len] = 0;
+
+               for (genfs_p = NULL, genfs = p->genfs; genfs;
+                    genfs_p = genfs, genfs = genfs->next) {
+                       rc = -EINVAL;
+                       if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+                               printk(KERN_ERR "SELinux:  dup genfs fstype %s\n",
+                                      newgenfs->fstype);
+                               goto out;
+                       }
+                       if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+                               break;
+               }
+               newgenfs->next = genfs;
+               if (genfs_p)
+                       genfs_p->next = newgenfs;
+               else
+                       p->genfs = newgenfs;
+               genfs = newgenfs;
+               newgenfs = NULL;
+
+               rc = next_entry(buf, fp, sizeof(u32));
+               if (rc)
+                       goto out;
+
+               nel2 = le32_to_cpu(buf[0]);
+               for (j = 0; j < nel2; j++) {
+                       rc = next_entry(buf, fp, sizeof(u32));
+                       if (rc)
+                               goto out;
+                       len = le32_to_cpu(buf[0]);
+
+                       rc = -ENOMEM;
+                       newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+                       if (!newc)
+                               goto out;
+
+                       rc = -ENOMEM;
+                       newc->u.name = kmalloc(len + 1, GFP_KERNEL);
+                       if (!newc->u.name)
+                               goto out;
+
+                       rc = next_entry(newc->u.name, fp, len);
+                       if (rc)
+                               goto out;
+                       newc->u.name[len] = 0;
+
+                       rc = next_entry(buf, fp, sizeof(u32));
+                       if (rc)
+                               goto out;
+
+                       newc->v.sclass = le32_to_cpu(buf[0]);
+                       rc = context_read_and_validate(&newc->context[0], p, fp);
+                       if (rc)
+                               goto out;
+
+                       for (l = NULL, c = genfs->head; c;
+                            l = c, c = c->next) {
+                               rc = -EINVAL;
+                               if (!strcmp(newc->u.name, c->u.name) &&
+                                   (!c->v.sclass || !newc->v.sclass ||
+                                    newc->v.sclass == c->v.sclass)) {
+                                       printk(KERN_ERR "SELinux:  dup genfs entry (%s,%s)\n",
+                                              genfs->fstype, c->u.name);
+                                       goto out;
+                               }
+                               len = strlen(newc->u.name);
+                               len2 = strlen(c->u.name);
+                               if (len > len2)
+                                       break;
+                       }
+
+                       newc->next = c;
+                       if (l)
+                               l->next = newc;
+                       else
+                               genfs->head = newc;
+                       newc = NULL;
+               }
+       }
+       rc = 0;
+out:
+       if (newgenfs)
+               kfree(newgenfs->fstype);
+       kfree(newgenfs);
+       ocontext_destroy(newc, OCON_FSUSE);
+
+       return rc;
+}
+
+static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+                        void *fp)
+{
+       int i, j, rc;
+       u32 nel, len;
+       __le32 buf[3];
+       struct ocontext *l, *c;
+       u32 nodebuf[8];
+
+       for (i = 0; i < info->ocon_num; i++) {
+               rc = next_entry(buf, fp, sizeof(u32));
+               if (rc)
+                       goto out;
+               nel = le32_to_cpu(buf[0]);
+
+               l = NULL;
+               for (j = 0; j < nel; j++) {
+                       rc = -ENOMEM;
+                       c = kzalloc(sizeof(*c), GFP_KERNEL);
+                       if (!c)
+                               goto out;
+                       if (l)
+                               l->next = c;
+                       else
+                               p->ocontexts[i] = c;
+                       l = c;
+
+                       switch (i) {
+                       case OCON_ISID:
+                               rc = next_entry(buf, fp, sizeof(u32));
+                               if (rc)
+                                       goto out;
+
+                               c->sid[0] = le32_to_cpu(buf[0]);
+                               rc = context_read_and_validate(&c->context[0], p, fp);
+                               if (rc)
+                                       goto out;
+                               break;
+                       case OCON_FS:
+                       case OCON_NETIF:
+                               rc = next_entry(buf, fp, sizeof(u32));
+                               if (rc)
+                                       goto out;
+                               len = le32_to_cpu(buf[0]);
+
+                               rc = -ENOMEM;
+                               c->u.name = kmalloc(len + 1, GFP_KERNEL);
+                               if (!c->u.name)
+                                       goto out;
+
+                               rc = next_entry(c->u.name, fp, len);
+                               if (rc)
+                                       goto out;
+
+                               c->u.name[len] = 0;
+                               rc = context_read_and_validate(&c->context[0], p, fp);
+                               if (rc)
+                                       goto out;
+                               rc = context_read_and_validate(&c->context[1], p, fp);
+                               if (rc)
+                                       goto out;
+                               break;
+                       case OCON_PORT:
+                               rc = next_entry(buf, fp, sizeof(u32)*3);
+                               if (rc)
+                                       goto out;
+                               c->u.port.protocol = le32_to_cpu(buf[0]);
+                               c->u.port.low_port = le32_to_cpu(buf[1]);
+                               c->u.port.high_port = le32_to_cpu(buf[2]);
+                               rc = context_read_and_validate(&c->context[0], p, fp);
+                               if (rc)
+                                       goto out;
+                               break;
+                       case OCON_NODE:
+                               rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
+                               if (rc)
+                                       goto out;
+                               c->u.node.addr = nodebuf[0]; /* network order */
+                               c->u.node.mask = nodebuf[1]; /* network order */
+                               rc = context_read_and_validate(&c->context[0], p, fp);
+                               if (rc)
+                                       goto out;
+                               break;
+                       case OCON_FSUSE:
+                               rc = next_entry(buf, fp, sizeof(u32)*2);
+                               if (rc)
+                                       goto out;
+
+                               rc = -EINVAL;
+                               c->v.behavior = le32_to_cpu(buf[0]);
+                               if (c->v.behavior > SECURITY_FS_USE_NONE)
+                                       goto out;
+
+                               rc = -ENOMEM;
+                               len = le32_to_cpu(buf[1]);
+                               c->u.name = kmalloc(len + 1, GFP_KERNEL);
+                               if (!c->u.name)
+                                       goto out;
+
+                               rc = next_entry(c->u.name, fp, len);
+                               if (rc)
+                                       goto out;
+                               c->u.name[len] = 0;
+                               rc = context_read_and_validate(&c->context[0], p, fp);
+                               if (rc)
+                                       goto out;
+                               break;
+                       case OCON_NODE6: {
+                               int k;
+
+                               rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
+                               if (rc)
+                                       goto out;
+                               for (k = 0; k < 4; k++)
+                                       c->u.node6.addr[k] = nodebuf[k];
+                               for (k = 0; k < 4; k++)
+                                       c->u.node6.mask[k] = nodebuf[k+4];
+                               rc = context_read_and_validate(&c->context[0], p, fp);
+                               if (rc)
+                                       goto out;
+                               break;
+                       }
+                       }
+               }
+       }
+       rc = 0;
+out:
+       return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1709,16 +2046,12 @@ int policydb_read(struct policydb *p, void *fp)
 {
        struct role_allow *ra, *lra;
        struct role_trans *tr, *ltr;
-       struct ocontext *l, *c, *newc;
-       struct genfs *genfs_p, *genfs, *newgenfs;
        int i, j, rc;
        __le32 buf[4];
-       u32 nodebuf[8];
-       u32 len, len2, nprim, nel, nel2;
+       u32 len, nprim, nel;
+
        char *policydb_str;
        struct policydb_compat_info *info;
-       struct range_trans *rt;
-       struct mls_range *r;
 
        rc = policydb_init(p);
        if (rc)
@@ -1919,294 +2252,45 @@ int policydb_read(struct policydb *p, void *fp)
        if (!p->process_trans_perms)
                goto bad;
 
-       for (i = 0; i < info->ocon_num; i++) {
-               rc = next_entry(buf, fp, sizeof(u32));
-               if (rc < 0)
-                       goto bad;
-               nel = le32_to_cpu(buf[0]);
-               l = NULL;
-               for (j = 0; j < nel; j++) {
-                       c = kzalloc(sizeof(*c), GFP_KERNEL);
-                       if (!c) {
-                               rc = -ENOMEM;
-                               goto bad;
-                       }
-                       if (l)
-                               l->next = c;
-                       else
-                               p->ocontexts[i] = c;
-                       l = c;
-                       rc = -EINVAL;
-                       switch (i) {
-                       case OCON_ISID:
-                               rc = next_entry(buf, fp, sizeof(u32));
-                               if (rc < 0)
-                                       goto bad;
-                               c->sid[0] = le32_to_cpu(buf[0]);
-                               rc = context_read_and_validate(&c->context[0], p, fp);
-                               if (rc)
-                                       goto bad;
-                               break;
-                       case OCON_FS:
-                       case OCON_NETIF:
-                               rc = next_entry(buf, fp, sizeof(u32));
-                               if (rc < 0)
-                                       goto bad;
-                               len = le32_to_cpu(buf[0]);
-                               c->u.name = kmalloc(len + 1, GFP_KERNEL);
-                               if (!c->u.name) {
-                                       rc = -ENOMEM;
-                                       goto bad;
-                               }
-                               rc = next_entry(c->u.name, fp, len);
-                               if (rc < 0)
-                                       goto bad;
-                               c->u.name[len] = 0;
-                               rc = context_read_and_validate(&c->context[0], p, fp);
-                               if (rc)
-                                       goto bad;
-                               rc = context_read_and_validate(&c->context[1], p, fp);
-                               if (rc)
-                                       goto bad;
-                               break;
-                       case OCON_PORT:
-                               rc = next_entry(buf, fp, sizeof(u32)*3);
-                               if (rc < 0)
-                                       goto bad;
-                               c->u.port.protocol = le32_to_cpu(buf[0]);
-                               c->u.port.low_port = le32_to_cpu(buf[1]);
-                               c->u.port.high_port = le32_to_cpu(buf[2]);
-                               rc = context_read_and_validate(&c->context[0], p, fp);
-                               if (rc)
-                                       goto bad;
-                               break;
-                       case OCON_NODE:
-                               rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
-                               if (rc < 0)
-                                       goto bad;
-                               c->u.node.addr = nodebuf[0]; /* network order */
-                               c->u.node.mask = nodebuf[1]; /* network order */
-                               rc = context_read_and_validate(&c->context[0], p, fp);
-                               if (rc)
-                                       goto bad;
-                               break;
-                       case OCON_FSUSE:
-                               rc = next_entry(buf, fp, sizeof(u32)*2);
-                               if (rc < 0)
-                                       goto bad;
-                               c->v.behavior = le32_to_cpu(buf[0]);
-                               if (c->v.behavior > SECURITY_FS_USE_NONE)
-                                       goto bad;
-                               len = le32_to_cpu(buf[1]);
-                               c->u.name = kmalloc(len + 1, GFP_KERNEL);
-                               if (!c->u.name) {
-                                       rc = -ENOMEM;
-                                       goto bad;
-                               }
-                               rc = next_entry(c->u.name, fp, len);
-                               if (rc < 0)
-                                       goto bad;
-                               c->u.name[len] = 0;
-                               rc = context_read_and_validate(&c->context[0], p, fp);
-                               if (rc)
-                                       goto bad;
-                               break;
-                       case OCON_NODE6: {
-                               int k;
-
-                               rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
-                               if (rc < 0)
-                                       goto bad;
-                               for (k = 0; k < 4; k++)
-                                       c->u.node6.addr[k] = nodebuf[k];
-                               for (k = 0; k < 4; k++)
-                                       c->u.node6.mask[k] = nodebuf[k+4];
-                               if (context_read_and_validate(&c->context[0], p, fp))
-                                       goto bad;
-                               break;
-                       }
-                       }
-               }
-       }
-
-       rc = next_entry(buf, fp, sizeof(u32));
-       if (rc < 0)
+       rc = ocontext_read(p, info, fp);
+       if (rc)
                goto bad;
-       nel = le32_to_cpu(buf[0]);
-       genfs_p = NULL;
-       rc = -EINVAL;
-       for (i = 0; i < nel; i++) {
-               rc = next_entry(buf, fp, sizeof(u32));
-               if (rc < 0)
-                       goto bad;
-               len = le32_to_cpu(buf[0]);
-               newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
-               if (!newgenfs) {
-                       rc = -ENOMEM;
-                       goto bad;
-               }
 
-               newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
-               if (!newgenfs->fstype) {
-                       rc = -ENOMEM;
-                       kfree(newgenfs);
-                       goto bad;
-               }
-               rc = next_entry(newgenfs->fstype, fp, len);
-               if (rc < 0) {
-                       kfree(newgenfs->fstype);
-                       kfree(newgenfs);
-                       goto bad;
-               }
-               newgenfs->fstype[len] = 0;
-               for (genfs_p = NULL, genfs = p->genfs; genfs;
-                    genfs_p = genfs, genfs = genfs->next) {
-                       if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
-                               printk(KERN_ERR "SELinux:  dup genfs "
-                                      "fstype %s\n", newgenfs->fstype);
-                               kfree(newgenfs->fstype);
-                               kfree(newgenfs);
-                               goto bad;
-                       }
-                       if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
-                               break;
-               }
-               newgenfs->next = genfs;
-               if (genfs_p)
-                       genfs_p->next = newgenfs;
-               else
-                       p->genfs = newgenfs;
-               rc = next_entry(buf, fp, sizeof(u32));
-               if (rc < 0)
-                       goto bad;
-               nel2 = le32_to_cpu(buf[0]);
-               for (j = 0; j < nel2; j++) {
-                       rc = next_entry(buf, fp, sizeof(u32));
-                       if (rc < 0)
-                               goto bad;
-                       len = le32_to_cpu(buf[0]);
-
-                       newc = kzalloc(sizeof(*newc), GFP_KERNEL);
-                       if (!newc) {
-                               rc = -ENOMEM;
-                               goto bad;
-                       }
-
-                       newc->u.name = kmalloc(len + 1, GFP_KERNEL);
-                       if (!newc->u.name) {
-                               rc = -ENOMEM;
-                               goto bad_newc;
-                       }
-                       rc = next_entry(newc->u.name, fp, len);
-                       if (rc < 0)
-                               goto bad_newc;
-                       newc->u.name[len] = 0;
-                       rc = next_entry(buf, fp, sizeof(u32));
-                       if (rc < 0)
-                               goto bad_newc;
-                       newc->v.sclass = le32_to_cpu(buf[0]);
-                       if (context_read_and_validate(&newc->context[0], p, fp))
-                               goto bad_newc;
-                       for (l = NULL, c = newgenfs->head; c;
-                            l = c, c = c->next) {
-                               if (!strcmp(newc->u.name, c->u.name) &&
-                                   (!c->v.sclass || !newc->v.sclass ||
-                                    newc->v.sclass == c->v.sclass)) {
-                                       printk(KERN_ERR "SELinux:  dup genfs "
-                                              "entry (%s,%s)\n",
-                                              newgenfs->fstype, c->u.name);
-                                       goto bad_newc;
-                               }
-                               len = strlen(newc->u.name);
-                               len2 = strlen(c->u.name);
-                               if (len > len2)
-                                       break;
-                       }
+       rc = genfs_read(p, fp);
+       if (rc)
+               goto bad;
 
-                       newc->next = c;
-                       if (l)
-                               l->next = newc;
-                       else
-                               newgenfs->head = newc;
-               }
-       }
+       rc = range_read(p, fp);
+       if (rc)
+               goto bad;
 
-       if (p->policyvers >= POLICYDB_VERSION_MLS) {
-               int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
-               rc = next_entry(buf, fp, sizeof(u32));
-               if (rc < 0)
-                       goto bad;
-               nel = le32_to_cpu(buf[0]);
-               for (i = 0; i < nel; i++) {
-                       rt = kzalloc(sizeof(*rt), GFP_KERNEL);
-                       if (!rt) {
-                               rc = -ENOMEM;
-                               goto bad;
-                       }
-                       rc = next_entry(buf, fp, (sizeof(u32) * 2));
-                       if (rc < 0) {
-                               kfree(rt);
-                               goto bad;
-                       }
-                       rt->source_type = le32_to_cpu(buf[0]);
-                       rt->target_type = le32_to_cpu(buf[1]);
-                       if (new_rangetr) {
-                               rc = next_entry(buf, fp, sizeof(u32));
-                               if (rc < 0) {
-                                       kfree(rt);
-                                       goto bad;
-                               }
-                               rt->target_class = le32_to_cpu(buf[0]);
-                       } else
-                               rt->target_class = p->process_class;
-                       if (!policydb_type_isvalid(p, rt->source_type) ||
-                           !policydb_type_isvalid(p, rt->target_type) ||
-                           !policydb_class_isvalid(p, rt->target_class)) {
-                               kfree(rt);
-                               rc = -EINVAL;
-                               goto bad;
-                       }
-                       r = kzalloc(sizeof(*r), GFP_KERNEL);
-                       if (!r) {
-                               kfree(rt);
-                               rc = -ENOMEM;
-                               goto bad;
-                       }
-                       rc = mls_read_range_helper(r, fp);
-                       if (rc) {
-                               kfree(rt);
-                               kfree(r);
-                               goto bad;
-                       }
-                       if (!mls_range_isvalid(p, r)) {
-                               printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
-                               kfree(rt);
-                               kfree(r);
-                               goto bad;
-                       }
-                       rc = hashtab_insert(p->range_tr, rt, r);
-                       if (rc) {
-                               kfree(rt);
-                               kfree(r);
-                               goto bad;
-                       }
-               }
-               rangetr_hash_eval(p->range_tr);
-       }
+       rc = -ENOMEM;
+       p->type_attr_map_array = flex_array_alloc(sizeof(struct ebitmap),
+                                                 p->p_types.nprim,
+                                                 GFP_KERNEL | __GFP_ZERO);
+       if (!p->type_attr_map_array)
+               goto bad;
 
-       p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL);
-       if (!p->type_attr_map)
+       /* preallocate so we don't have to worry about the put ever failing */
+       rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1,
+                                GFP_KERNEL | __GFP_ZERO);
+       if (rc)
                goto bad;
 
        for (i = 0; i < p->p_types.nprim; i++) {
-               ebitmap_init(&p->type_attr_map[i]);
+               struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+
+               BUG_ON(!e);
+               ebitmap_init(e);
                if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
-                       if (ebitmap_read(&p->type_attr_map[i], fp))
+                       rc = ebitmap_read(e, fp);
+                       if (rc)
                                goto bad;
                }
                /* add the type itself as the degenerate case */
-               if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
-                               goto bad;
+               rc = ebitmap_set_bit(e, i, 1);
+               if (rc)
+                       goto bad;
        }
 
        rc = policydb_bounds_sanity_check(p);
@@ -2216,8 +2300,6 @@ int policydb_read(struct policydb *p, void *fp)
        rc = 0;
 out:
        return rc;
-bad_newc:
-       ocontext_destroy(newc, OCON_FSUSE);
 bad:
        if (!rc)
                rc = -EINVAL;
index 26d9adf8542b313982df291d6357d04415192b03..310e94442cb8b3535a8774b952de45ba0180794e 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _SS_POLICYDB_H_
 #define _SS_POLICYDB_H_
 
+#include <linux/flex_array.h>
+
 #include "symtab.h"
 #include "avtab.h"
 #include "sidtab.h"
@@ -246,7 +248,7 @@ struct policydb {
        struct hashtab *range_tr;
 
        /* type -> attribute reverse mapping */
-       struct ebitmap *type_attr_map;
+       struct flex_array *type_attr_map_array;
 
        struct ebitmap policycaps;
 
index 1de60ce90d9a237cd4cbfda6a4a34adb6c1de618..9ea2feca3cd4f7b572361543fdf1b265002cecfb 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/audit.h>
 #include <linux/mutex.h>
 #include <linux/selinux.h>
+#include <linux/flex_array.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
@@ -626,8 +627,10 @@ static void context_struct_compute_av(struct context *scontext,
         */
        avkey.target_class = tclass;
        avkey.specified = AVTAB_AV;
-       sattr = &policydb.type_attr_map[scontext->type - 1];
-       tattr = &policydb.type_attr_map[tcontext->type - 1];
+       sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
+       BUG_ON(!sattr);
+       tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
+       BUG_ON(!tattr);
        ebitmap_for_each_positive_bit(sattr, snode, i) {
                ebitmap_for_each_positive_bit(tattr, tnode, j) {
                        avkey.source_type = i + 1;
index bcf9f620426e04dfd102895bcf89b7f5d6b761bc..160326ee99e58b0d47388dcb98493a7d1bb0905f 100644 (file)
@@ -36,7 +36,7 @@ int symtab_init(struct symtab *s, unsigned int size)
 {
        s->table = hashtab_create(symhash, symcmp, size);
        if (!s->table)
-               return -1;
+               return -ENOMEM;
        s->nprim = 0;
        return 0;
 }
index c6e9acae72e4b74b9e75f037845e54b61fce6163..43ae747a5aa4e60746fdc7cdb15ec5cd3bb42b52 100644 (file)
@@ -123,16 +123,6 @@ struct smack_known {
 #define SMK_FSHAT      "smackfshat="
 #define SMK_FSROOT     "smackfsroot="
 
-/*
- * xattr names
- */
-#define XATTR_SMACK_SUFFIX     "SMACK64"
-#define XATTR_SMACK_IPIN       "SMACK64IPIN"
-#define XATTR_SMACK_IPOUT      "SMACK64IPOUT"
-#define XATTR_NAME_SMACK       XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
-#define XATTR_NAME_SMACKIPIN   XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
-#define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
-
 #define SMACK_CIPSO_OPTION     "-CIPSO"
 
 /*
index 0f2fc480fc612f08e9701d319018efad76ded438..9192ba366a4c90971c11ed25904ee9bc7e4d675d 100644 (file)
@@ -598,6 +598,8 @@ static int smack_inode_rename(struct inode *old_inode,
 static int smack_inode_permission(struct inode *inode, int mask)
 {
        struct smk_audit_info ad;
+
+       mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
        /*
         * No permission to check. Existence test. Yup, it's there.
         */
@@ -2191,7 +2193,7 @@ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
 
 /**
  * smack_d_instantiate - Make sure the blob is correct on an inode
- * @opt_dentry: unused
+ * @opt_dentry: dentry where inode will be attached
  * @inode: the object
  *
  * Set the inode's security blob if it hasn't been done already.
@@ -2310,20 +2312,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                /*
                 * Get the dentry for xattr.
                 */
-               if (opt_dentry == NULL) {
-                       dp = d_find_alias(inode);
-                       if (dp == NULL)
-                               break;
-               } else {
-                       dp = dget(opt_dentry);
-                       if (dp == NULL)
-                               break;
-               }
-
+               dp = dget(opt_dentry);
                fetched = smk_fetch(inode, dp);
                if (fetched != NULL)
                        final = fetched;
-
                dput(dp);
                break;
        }
index 4fb39030f6bd196e3d8f0b9aa64c7120dead18ec..91640e96bd065776af1ffeffa23f06b5208ff368 100644 (file)
@@ -1 +1 @@
-obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o
+obj-y = common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
index b5dbdc9ff73c944b7ecd0583fa786c3d29f72726..ef43995119a453401dd768adfa5ae41a2602dd3a 100644 (file)
  *
  * Common functions for TOMOYO.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/security.h>
-#include <linux/hardirq.h>
 #include "common.h"
 
-/* Lock for protecting policy. */
-DEFINE_MUTEX(tomoyo_policy_lock);
+static struct tomoyo_profile tomoyo_default_profile = {
+       .learning = &tomoyo_default_profile.preference,
+       .permissive = &tomoyo_default_profile.preference,
+       .enforcing = &tomoyo_default_profile.preference,
+       .preference.enforcing_verbose = true,
+       .preference.learning_max_entry = 2048,
+       .preference.learning_verbose = false,
+       .preference.permissive_verbose = true
+};
 
-/* Has loading policy done? */
-bool tomoyo_policy_loaded;
+/* Profile version. Currently only 20090903 is defined. */
+static unsigned int tomoyo_profile_version;
+
+/* Profile table. Memory is allocated as needed. */
+static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
 
 /* String table for functionality that takes 4 modes. */
-static const char *tomoyo_mode_4[4] = {
+static const char *tomoyo_mode[4] = {
        "disabled", "learning", "permissive", "enforcing"
 };
-/* String table for functionality that takes 2 modes. */
-static const char *tomoyo_mode_2[4] = {
-       "disabled", "enabled", "enabled", "enabled"
-};
 
-/*
- * tomoyo_control_array is a static data which contains
- *
- *  (1) functionality name used by /sys/kernel/security/tomoyo/profile .
- *  (2) initial values for "struct tomoyo_profile".
- *  (3) max values for "struct tomoyo_profile".
- */
-static struct {
-       const char *keyword;
-       unsigned int current_value;
-       const unsigned int max_value;
-} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
-       [TOMOYO_MAC_FOR_FILE]     = { "MAC_FOR_FILE",        0,       3 },
-       [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
-       [TOMOYO_VERBOSE]          = { "TOMOYO_VERBOSE",      1,       1 },
+/* String table for /sys/kernel/security/tomoyo/profile */
+static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+                                      + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+       [TOMOYO_MAC_FILE_EXECUTE]    = "file::execute",
+       [TOMOYO_MAC_FILE_OPEN]       = "file::open",
+       [TOMOYO_MAC_FILE_CREATE]     = "file::create",
+       [TOMOYO_MAC_FILE_UNLINK]     = "file::unlink",
+       [TOMOYO_MAC_FILE_MKDIR]      = "file::mkdir",
+       [TOMOYO_MAC_FILE_RMDIR]      = "file::rmdir",
+       [TOMOYO_MAC_FILE_MKFIFO]     = "file::mkfifo",
+       [TOMOYO_MAC_FILE_MKSOCK]     = "file::mksock",
+       [TOMOYO_MAC_FILE_TRUNCATE]   = "file::truncate",
+       [TOMOYO_MAC_FILE_SYMLINK]    = "file::symlink",
+       [TOMOYO_MAC_FILE_REWRITE]    = "file::rewrite",
+       [TOMOYO_MAC_FILE_MKBLOCK]    = "file::mkblock",
+       [TOMOYO_MAC_FILE_MKCHAR]     = "file::mkchar",
+       [TOMOYO_MAC_FILE_LINK]       = "file::link",
+       [TOMOYO_MAC_FILE_RENAME]     = "file::rename",
+       [TOMOYO_MAC_FILE_CHMOD]      = "file::chmod",
+       [TOMOYO_MAC_FILE_CHOWN]      = "file::chown",
+       [TOMOYO_MAC_FILE_CHGRP]      = "file::chgrp",
+       [TOMOYO_MAC_FILE_IOCTL]      = "file::ioctl",
+       [TOMOYO_MAC_FILE_CHROOT]     = "file::chroot",
+       [TOMOYO_MAC_FILE_MOUNT]      = "file::mount",
+       [TOMOYO_MAC_FILE_UMOUNT]     = "file::umount",
+       [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root",
+       [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
 };
 
-/*
- * tomoyo_profile is a structure which is used for holding the mode of access
- * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing.
- * An administrator can define up to 256 profiles.
- * The ->profile of "struct tomoyo_domain_info" is used for remembering
- * the profile's number (0 - 255) assigned to that domain.
- */
-static struct tomoyo_profile {
-       unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
-       const struct tomoyo_path_info *comment;
-} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
-
 /* Permit policy management by non-root user? */
 static bool tomoyo_manage_by_non_root;
 
 /* Utility functions. */
 
-/* Open operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_open_control(const u8 type, struct file *file);
-/* Close /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_close_control(struct file *file);
-/* Read operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_read_control(struct file *file, char __user *buffer,
-                              const int buffer_len);
-/* Write operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
-                               const int buffer_len);
-
-/**
- * tomoyo_parse_name_union - Parse a tomoyo_name_union.
- *
- * @filename: Name or name group.
- * @ptr:      Pointer to "struct tomoyo_name_union".
- *
- * Returns true on success, false otherwise.
- */
-bool tomoyo_parse_name_union(const char *filename,
-                            struct tomoyo_name_union *ptr)
-{
-       if (!tomoyo_is_correct_path(filename, 0, 0, 0))
-               return false;
-       if (filename[0] == '@') {
-               ptr->group = tomoyo_get_path_group(filename + 1);
-               ptr->is_group = true;
-               return ptr->group != NULL;
-       }
-       ptr->filename = tomoyo_get_name(filename);
-       ptr->is_group = false;
-       return ptr->filename != NULL;
-}
-
 /**
- * tomoyo_print_name_union - Print a tomoyo_name_union.
+ * tomoyo_yesno - Return "yes" or "no".
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to "struct tomoyo_name_union".
- *
- * Returns true on success, false otherwise.
+ * @value: Bool value.
  */
-static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,
-                                const struct tomoyo_name_union *ptr)
+static const char *tomoyo_yesno(const unsigned int value)
 {
-       int pos = head->read_avail;
-       if (pos && head->read_buf[pos - 1] == ' ')
-               head->read_avail--;
-       if (ptr->is_group)
-               return tomoyo_io_printf(head, " @%s",
-                                       ptr->group->group_name->name);
-       return tomoyo_io_printf(head, " %s", ptr->filename->name);
+       return value ? "yes" : "no";
 }
 
-/**
- * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
- *
- * @str: Pointer to the string.
- *
- * Returns true if @str is a \ooo style octal value, false otherwise.
- *
- * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
- * This function verifies that \ooo is in valid range.
- */
-static inline bool tomoyo_is_byte_range(const char *str)
+static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
 {
-       return *str >= '0' && *str++ <= '3' &&
-               *str >= '0' && *str++ <= '7' &&
-               *str >= '0' && *str <= '7';
-}
-
-/**
- * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
- *
- * @c: The character to check.
- *
- * Returns true if @c is an alphabet character, false otherwise.
- */
-static inline bool tomoyo_is_alphabet_char(const char c)
-{
-       return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
-}
-
-/**
- * tomoyo_make_byte - Make byte value from three octal characters.
- *
- * @c1: The first character.
- * @c2: The second character.
- * @c3: The third character.
- *
- * Returns byte value.
- */
-static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
-{
-       return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+       va_list args;
+       const int pos = strlen(buffer);
+       va_start(args, fmt);
+       vsnprintf(buffer + pos, len - pos - 1, fmt, args);
+       va_end(args);
 }
 
 /**
- * tomoyo_str_starts - Check whether the given string starts with the given keyword.
- *
- * @src:  Pointer to pointer to the string.
- * @find: Pointer to the keyword.
+ * tomoyo_flush - Flush queued string to userspace's buffer.
  *
- * Returns true if @src starts with @find, false otherwise.
+ * @head:   Pointer to "struct tomoyo_io_buffer".
  *
- * The @src is updated to point the first character after the @find
- * if @src starts with @find.
+ * Returns true if all data was flushed, false otherwise.
  */
-static bool tomoyo_str_starts(char **src, const char *find)
+static bool tomoyo_flush(struct tomoyo_io_buffer *head)
 {
-       const int len = strlen(find);
-       char *tmp = *src;
-
-       if (strncmp(tmp, find, len))
-               return false;
-       tmp += len;
-       *src = tmp;
+       while (head->r.w_pos) {
+               const char *w = head->r.w[0];
+               int len = strlen(w);
+               if (len) {
+                       if (len > head->read_user_buf_avail)
+                               len = head->read_user_buf_avail;
+                       if (!len)
+                               return false;
+                       if (copy_to_user(head->read_user_buf, w, len))
+                               return false;
+                       head->read_user_buf_avail -= len;
+                       head->read_user_buf += len;
+                       w += len;
+               }
+               if (*w) {
+                       head->r.w[0] = w;
+                       return false;
+               }
+               /* Add '\0' for query. */
+               if (head->poll) {
+                       if (!head->read_user_buf_avail ||
+                           copy_to_user(head->read_user_buf, "", 1))
+                               return false;
+                       head->read_user_buf_avail--;
+                       head->read_user_buf++;
+               }
+               head->r.w_pos--;
+               for (len = 0; len < head->r.w_pos; len++)
+                       head->r.w[len] = head->r.w[len + 1];
+       }
+       head->r.avail = 0;
        return true;
 }
 
 /**
- * tomoyo_normalize_line - Format string.
- *
- * @buffer: The line to normalize.
+ * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
  *
- * Leading and trailing whitespaces are removed.
- * Multiple whitespaces are packed into single space.
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ * @string: String to print.
  *
- * Returns nothing.
+ * Note that @string has to be kept valid until @head is kfree()d.
+ * This means that char[] allocated on stack memory cannot be passed to
+ * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
  */
-static void tomoyo_normalize_line(unsigned char *buffer)
+static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
 {
-       unsigned char *sp = buffer;
-       unsigned char *dp = buffer;
-       bool first = true;
-
-       while (tomoyo_is_invalid(*sp))
-               sp++;
-       while (*sp) {
-               if (!first)
-                       *dp++ = ' ';
-               first = false;
-               while (tomoyo_is_valid(*sp))
-                       *dp++ = *sp++;
-               while (tomoyo_is_invalid(*sp))
-                       sp++;
-       }
-       *dp = '\0';
+       if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
+               head->r.w[head->r.w_pos++] = string;
+               tomoyo_flush(head);
+       } else
+               WARN_ON(1);
 }
 
 /**
- * tomoyo_tokenize - Tokenize string.
+ * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
  *
- * @buffer: The line to tokenize.
- * @w:      Pointer to "char *".
- * @size:   Sizeof @w .
- *
- * Returns true on success, false otherwise.
- */
-bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
-{
-       int count = size / sizeof(char *);
-       int i;
-       for (i = 0; i < count; i++)
-               w[i] = "";
-       for (i = 0; i < count; i++) {
-               char *cp = strchr(buffer, ' ');
-               if (cp)
-                       *cp = '\0';
-               w[i] = buffer;
-               if (!cp)
-                       break;
-               buffer = cp + 1;
-       }
-       return i < count || !*buffer;
-}
-
-/**
- * tomoyo_is_correct_path - Validate a pathname.
- * @filename:     The pathname to check.
- * @start_type:   Should the pathname start with '/'?
- *                1 = must / -1 = must not / 0 = don't care
- * @pattern_type: Can the pathname contain a wildcard?
- *                1 = must / -1 = must not / 0 = don't care
- * @end_type:     Should the pathname end with '/'?
- *                1 = must / -1 = must not / 0 = don't care
- *
- * Check whether the given filename follows the naming rules.
- * Returns true if @filename follows the naming rules, false otherwise.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @fmt:  The printf()'s format string, followed by parameters.
  */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
-                           const s8 pattern_type, const s8 end_type)
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
 {
-       const char *const start = filename;
-       bool in_repetition = false;
-       bool contains_pattern = false;
-       unsigned char c;
-       unsigned char d;
-       unsigned char e;
-
-       if (!filename)
-               goto out;
-       c = *filename;
-       if (start_type == 1) { /* Must start with '/' */
-               if (c != '/')
-                       goto out;
-       } else if (start_type == -1) { /* Must not start with '/' */
-               if (c == '/')
-                       goto out;
-       }
-       if (c)
-               c = *(filename + strlen(filename) - 1);
-       if (end_type == 1) { /* Must end with '/' */
-               if (c != '/')
-                       goto out;
-       } else if (end_type == -1) { /* Must not end with '/' */
-               if (c == '/')
-                       goto out;
-       }
-       while (1) {
-               c = *filename++;
-               if (!c)
-                       break;
-               if (c == '\\') {
-                       c = *filename++;
-                       switch (c) {
-                       case '\\':  /* "\\" */
-                               continue;
-                       case '$':   /* "\$" */
-                       case '+':   /* "\+" */
-                       case '?':   /* "\?" */
-                       case '*':   /* "\*" */
-                       case '@':   /* "\@" */
-                       case 'x':   /* "\x" */
-                       case 'X':   /* "\X" */
-                       case 'a':   /* "\a" */
-                       case 'A':   /* "\A" */
-                       case '-':   /* "\-" */
-                               if (pattern_type == -1)
-                                       break; /* Must not contain pattern */
-                               contains_pattern = true;
-                               continue;
-                       case '{':   /* "/\{" */
-                               if (filename - 3 < start ||
-                                   *(filename - 3) != '/')
-                                       break;
-                               if (pattern_type == -1)
-                                       break; /* Must not contain pattern */
-                               contains_pattern = true;
-                               in_repetition = true;
-                               continue;
-                       case '}':   /* "\}/" */
-                               if (*filename != '/')
-                                       break;
-                               if (!in_repetition)
-                                       break;
-                               in_repetition = false;
-                               continue;
-                       case '0':   /* "\ooo" */
-                       case '1':
-                       case '2':
-                       case '3':
-                               d = *filename++;
-                               if (d < '0' || d > '7')
-                                       break;
-                               e = *filename++;
-                               if (e < '0' || e > '7')
-                                       break;
-                               c = tomoyo_make_byte(c, d, e);
-                               if (tomoyo_is_invalid(c))
-                                       continue; /* pattern is not \000 */
-                       }
-                       goto out;
-               } else if (in_repetition && c == '/') {
-                       goto out;
-               } else if (tomoyo_is_invalid(c)) {
-                       goto out;
-               }
-       }
-       if (pattern_type == 1) { /* Must contain pattern */
-               if (!contains_pattern)
-                       goto out;
+       va_list args;
+       int len;
+       int pos = head->r.avail;
+       int size = head->readbuf_size - pos;
+       if (size <= 0)
+               return;
+       va_start(args, fmt);
+       len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
+       va_end(args);
+       if (pos + len >= head->readbuf_size) {
+               WARN_ON(1);
+               return;
        }
-       if (in_repetition)
-               goto out;
-       return true;
- out:
-       return false;
+       head->r.avail += len;
+       tomoyo_set_string(head, head->read_buf + pos);
 }
 
-/**
- * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
- * @domainname:   The domainname to check.
- *
- * Returns true if @domainname follows the naming rules, false otherwise.
- */
-bool tomoyo_is_correct_domain(const unsigned char *domainname)
+static void tomoyo_set_space(struct tomoyo_io_buffer *head)
 {
-       unsigned char c;
-       unsigned char d;
-       unsigned char e;
-
-       if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
-                                  TOMOYO_ROOT_NAME_LEN))
-               goto out;
-       domainname += TOMOYO_ROOT_NAME_LEN;
-       if (!*domainname)
-               return true;
-       do {
-               if (*domainname++ != ' ')
-                       goto out;
-               if (*domainname++ != '/')
-                       goto out;
-               while ((c = *domainname) != '\0' && c != ' ') {
-                       domainname++;
-                       if (c == '\\') {
-                               c = *domainname++;
-                               switch ((c)) {
-                               case '\\':  /* "\\" */
-                                       continue;
-                               case '0':   /* "\ooo" */
-                               case '1':
-                               case '2':
-                               case '3':
-                                       d = *domainname++;
-                                       if (d < '0' || d > '7')
-                                               break;
-                                       e = *domainname++;
-                                       if (e < '0' || e > '7')
-                                               break;
-                                       c = tomoyo_make_byte(c, d, e);
-                                       if (tomoyo_is_invalid(c))
-                                               /* pattern is not \000 */
-                                               continue;
-                               }
-                               goto out;
-                       } else if (tomoyo_is_invalid(c)) {
-                               goto out;
-                       }
-               }
-       } while (*domainname);
-       return true;
- out:
-       return false;
+       tomoyo_set_string(head, " ");
 }
 
-/**
- * tomoyo_is_domain_def - Check whether the given token can be a domainname.
- *
- * @buffer: The token to check.
- *
- * Returns true if @buffer possibly be a domainname, false otherwise.
- */
-bool tomoyo_is_domain_def(const unsigned char *buffer)
+static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
 {
-       return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+       tomoyo_set_string(head, "\n");
+       return !head->r.w_pos;
 }
 
 /**
- * tomoyo_find_domain - Find a domain by the given name.
- *
- * @domainname: The domainname to find.
- *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ * tomoyo_print_name_union - Print a tomoyo_name_union.
  *
- * Caller holds tomoyo_read_lock().
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_name_union".
  */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
+                                   const struct tomoyo_name_union *ptr)
 {
-       struct tomoyo_domain_info *domain;
-       struct tomoyo_path_info name;
-
-       name.name = domainname;
-       tomoyo_fill_path_info(&name);
-       list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-               if (!domain->is_deleted &&
-                   !tomoyo_pathcmp(&name, domain->domainname))
-                       return domain;
+       tomoyo_set_space(head);
+       if (ptr->is_group) {
+               tomoyo_set_string(head, "@");
+               tomoyo_set_string(head, ptr->group->group_name->name);
+       } else {
+               tomoyo_set_string(head, ptr->filename->name);
        }
-       return NULL;
 }
 
 /**
- * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
  *
- * @filename: The string to evaluate.
- *
- * Returns the initial length without a pattern in @filename.
+ * @head:       Pointer to "struct tomoyo_io_buffer".
+ * @ptr:        Pointer to "struct tomoyo_number_union".
  */
-static int tomoyo_const_part_length(const char *filename)
+static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+                                     const struct tomoyo_number_union *ptr)
 {
-       char c;
-       int len = 0;
-
-       if (!filename)
-               return 0;
-       while ((c = *filename++) != '\0') {
-               if (c != '\\') {
-                       len++;
-                       continue;
-               }
-               c = *filename++;
-               switch (c) {
-               case '\\':  /* "\\" */
-                       len += 2;
-                       continue;
-               case '0':   /* "\ooo" */
-               case '1':
-               case '2':
-               case '3':
-                       c = *filename++;
-                       if (c < '0' || c > '7')
+       tomoyo_set_space(head);
+       if (ptr->is_group) {
+               tomoyo_set_string(head, "@");
+               tomoyo_set_string(head, ptr->group->group_name->name);
+       } else {
+               int i;
+               unsigned long min = ptr->values[0];
+               const unsigned long max = ptr->values[1];
+               u8 min_type = ptr->min_type;
+               const u8 max_type = ptr->max_type;
+               char buffer[128];
+               buffer[0] = '\0';
+               for (i = 0; i < 2; i++) {
+                       switch (min_type) {
+                       case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+                               tomoyo_addprintf(buffer, sizeof(buffer),
+                                                "0x%lX", min);
                                break;
-                       c = *filename++;
-                       if (c < '0' || c > '7')
+                       case TOMOYO_VALUE_TYPE_OCTAL:
+                               tomoyo_addprintf(buffer, sizeof(buffer),
+                                                "0%lo", min);
                                break;
-                       len += 4;
-                       continue;
-               }
-               break;
-       }
-       return len;
-}
-
-/**
- * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
- *
- * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
- *
- * The caller sets "struct tomoyo_path_info"->name.
- */
-void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
-{
-       const char *name = ptr->name;
-       const int len = strlen(name);
-
-       ptr->const_len = tomoyo_const_part_length(name);
-       ptr->is_dir = len && (name[len - 1] == '/');
-       ptr->is_patterned = (ptr->const_len < len);
-       ptr->hash = full_name_hash(name, len);
-}
-
-/**
- * tomoyo_file_matches_pattern2 - Pattern matching without '/' character
- * and "\-" pattern.
- *
- * @filename:     The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern:      The start of pattern to compare.
- * @pattern_end:  The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern2(const char *filename,
-                                        const char *filename_end,
-                                        const char *pattern,
-                                        const char *pattern_end)
-{
-       while (filename < filename_end && pattern < pattern_end) {
-               char c;
-               if (*pattern != '\\') {
-                       if (*filename++ != *pattern++)
-                               return false;
-                       continue;
-               }
-               c = *filename;
-               pattern++;
-               switch (*pattern) {
-                       int i;
-                       int j;
-               case '?':
-                       if (c == '/') {
-                               return false;
-                       } else if (c == '\\') {
-                               if (filename[1] == '\\')
-                                       filename++;
-                               else if (tomoyo_is_byte_range(filename + 1))
-                                       filename += 3;
-                               else
-                                       return false;
-                       }
-                       break;
-               case '\\':
-                       if (c != '\\')
-                               return false;
-                       if (*++filename != '\\')
-                               return false;
-                       break;
-               case '+':
-                       if (!isdigit(c))
-                               return false;
-                       break;
-               case 'x':
-                       if (!isxdigit(c))
-                               return false;
-                       break;
-               case 'a':
-                       if (!tomoyo_is_alphabet_char(c))
-                               return false;
-                       break;
-               case '0':
-               case '1':
-               case '2':
-               case '3':
-                       if (c == '\\' && tomoyo_is_byte_range(filename + 1)
-                           && strncmp(filename + 1, pattern, 3) == 0) {
-                               filename += 3;
-                               pattern += 2;
+                       default:
+                               tomoyo_addprintf(buffer, sizeof(buffer),
+                                                "%lu", min);
                                break;
                        }
-                       return false; /* Not matched. */
-               case '*':
-               case '@':
-                       for (i = 0; i <= filename_end - filename; i++) {
-                               if (tomoyo_file_matches_pattern2(
-                                                   filename + i, filename_end,
-                                                   pattern + 1, pattern_end))
-                                       return true;
-                               c = filename[i];
-                               if (c == '.' && *pattern == '@')
-                                       break;
-                               if (c != '\\')
-                                       continue;
-                               if (filename[i + 1] == '\\')
-                                       i++;
-                               else if (tomoyo_is_byte_range(filename + i + 1))
-                                       i += 3;
-                               else
-                                       break; /* Bad pattern. */
-                       }
-                       return false; /* Not matched. */
-               default:
-                       j = 0;
-                       c = *pattern;
-                       if (c == '$') {
-                               while (isdigit(filename[j]))
-                                       j++;
-                       } else if (c == 'X') {
-                               while (isxdigit(filename[j]))
-                                       j++;
-                       } else if (c == 'A') {
-                               while (tomoyo_is_alphabet_char(filename[j]))
-                                       j++;
-                       }
-                       for (i = 1; i <= j; i++) {
-                               if (tomoyo_file_matches_pattern2(
-                                                   filename + i, filename_end,
-                                                   pattern + 1, pattern_end))
-                                       return true;
-                       }
-                       return false; /* Not matched or bad pattern. */
+                       if (min == max && min_type == max_type)
+                               break;
+                       tomoyo_addprintf(buffer, sizeof(buffer), "-");
+                       min_type = max_type;
+                       min = max;
                }
-               filename++;
-               pattern++;
+               tomoyo_io_printf(head, "%s", buffer);
        }
-       while (*pattern == '\\' &&
-              (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
-               pattern += 2;
-       return filename == filename_end && pattern == pattern_end;
 }
 
 /**
- * tomoyo_file_matches_pattern - Pattern matching without without '/' character.
- *
- * @filename:     The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern:      The start of pattern to compare.
- * @pattern_end:  The end of pattern to compare.
+ * tomoyo_assign_profile - Create a new profile.
  *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern(const char *filename,
-                                          const char *filename_end,
-                                          const char *pattern,
-                                          const char *pattern_end)
-{
-       const char *pattern_start = pattern;
-       bool first = true;
-       bool result;
-
-       while (pattern < pattern_end - 1) {
-               /* Split at "\-" pattern. */
-               if (*pattern++ != '\\' || *pattern++ != '-')
-                       continue;
-               result = tomoyo_file_matches_pattern2(filename,
-                                                     filename_end,
-                                                     pattern_start,
-                                                     pattern - 2);
-               if (first)
-                       result = !result;
-               if (result)
-                       return false;
-               first = false;
-               pattern_start = pattern;
-       }
-       result = tomoyo_file_matches_pattern2(filename, filename_end,
-                                             pattern_start, pattern_end);
-       return first ? result : !result;
-}
-
-/**
- * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
- *
- * @f: The start of string to check.
- * @p: The start of pattern to compare.
+ * @profile: Profile number to create.
  *
- * Returns true if @f matches @p, false otherwise.
+ * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
  */
-static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
+static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
 {
-       const char *f_delimiter;
-       const char *p_delimiter;
-
-       while (*f && *p) {
-               f_delimiter = strchr(f, '/');
-               if (!f_delimiter)
-                       f_delimiter = f + strlen(f);
-               p_delimiter = strchr(p, '/');
-               if (!p_delimiter)
-                       p_delimiter = p + strlen(p);
-               if (*p == '\\' && *(p + 1) == '{')
-                       goto recursive;
-               if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
-                                                p_delimiter))
-                       return false;
-               f = f_delimiter;
-               if (*f)
-                       f++;
-               p = p_delimiter;
-               if (*p)
-                       p++;
+       struct tomoyo_profile *ptr;
+       struct tomoyo_profile *entry;
+       if (profile >= TOMOYO_MAX_PROFILES)
+               return NULL;
+       ptr = tomoyo_profile_ptr[profile];
+       if (ptr)
+               return ptr;
+       entry = kzalloc(sizeof(*entry), GFP_NOFS);
+       if (mutex_lock_interruptible(&tomoyo_policy_lock))
+               goto out;
+       ptr = tomoyo_profile_ptr[profile];
+       if (!ptr && tomoyo_memory_ok(entry)) {
+               ptr = entry;
+               ptr->learning = &tomoyo_default_profile.preference;
+               ptr->permissive = &tomoyo_default_profile.preference;
+               ptr->enforcing = &tomoyo_default_profile.preference;
+               ptr->default_config = TOMOYO_CONFIG_DISABLED;
+               memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
+                      sizeof(ptr->config));
+               mb(); /* Avoid out-of-order execution. */
+               tomoyo_profile_ptr[profile] = ptr;
+               entry = NULL;
        }
-       /* Ignore trailing "\*" and "\@" in @pattern. */
-       while (*p == '\\' &&
-              (*(p + 1) == '*' || *(p + 1) == '@'))
-               p += 2;
-       return !*f && !*p;
- recursive:
-       /*
-        * The "\{" pattern is permitted only after '/' character.
-        * This guarantees that below "*(p - 1)" is safe.
-        * Also, the "\}" pattern is permitted only before '/' character
-        * so that "\{" + "\}" pair will not break the "\-" operator.
-        */
-       if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
-           *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
-               return false; /* Bad pattern. */
-       do {
-               /* Compare current component with pattern. */
-               if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
-                                                p_delimiter - 2))
-                       break;
-               /* Proceed to next component. */
-               f = f_delimiter;
-               if (!*f)
-                       break;
-               f++;
-               /* Continue comparison. */
-               if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
-                       return true;
-               f_delimiter = strchr(f, '/');
-       } while (f_delimiter);
-       return false; /* Not matched. */
-}
-
-/**
- * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
- *
- * @filename: The filename to check.
- * @pattern:  The pattern to compare.
- *
- * Returns true if matches, false otherwise.
- *
- * The following patterns are available.
- *   \\     \ itself.
- *   \ooo   Octal representation of a byte.
- *   \*     Zero or more repetitions of characters other than '/'.
- *   \@     Zero or more repetitions of characters other than '/' or '.'.
- *   \?     1 byte character other than '/'.
- *   \$     One or more repetitions of decimal digits.
- *   \+     1 decimal digit.
- *   \X     One or more repetitions of hexadecimal digits.
- *   \x     1 hexadecimal digit.
- *   \A     One or more repetitions of alphabet characters.
- *   \a     1 alphabet character.
- *
- *   \-     Subtraction operator.
- *
- *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
- *               /dir/dir/dir/ ).
- */
-bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
-                                const struct tomoyo_path_info *pattern)
-{
-       const char *f = filename->name;
-       const char *p = pattern->name;
-       const int len = pattern->const_len;
-
-       /* If @pattern doesn't contain pattern, I can use strcmp(). */
-       if (!pattern->is_patterned)
-               return !tomoyo_pathcmp(filename, pattern);
-       /* Don't compare directory and non-directory. */
-       if (filename->is_dir != pattern->is_dir)
-               return false;
-       /* Compare the initial length without patterns. */
-       if (strncmp(f, p, len))
-               return false;
-       f += len;
-       p += len;
-       return tomoyo_path_matches_pattern2(f, p);
+       mutex_unlock(&tomoyo_policy_lock);
+ out:
+       kfree(entry);
+       return ptr;
 }
 
 /**
- * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @fmt:  The printf()'s format string, followed by parameters.
+ * tomoyo_profile - Find a profile.
  *
- * Returns true if output was written, false otherwise.
+ * @profile: Profile number to find.
  *
- * The snprintf() will truncate, but tomoyo_io_printf() won't.
+ * Returns pointer to "struct tomoyo_profile".
  */
-bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+struct tomoyo_profile *tomoyo_profile(const u8 profile)
 {
-       va_list args;
-       int len;
-       int pos = head->read_avail;
-       int size = head->readbuf_size - pos;
-
-       if (size <= 0)
-               return false;
-       va_start(args, fmt);
-       len = vsnprintf(head->read_buf + pos, size, fmt, args);
-       va_end(args);
-       if (pos + len >= head->readbuf_size)
-               return false;
-       head->read_avail += len;
-       return true;
+       struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile];
+       if (!tomoyo_policy_loaded)
+               return &tomoyo_default_profile;
+       BUG_ON(!ptr);
+       return ptr;
 }
 
-/**
- * tomoyo_get_exe - Get tomoyo_realpath() of current process.
- *
- * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
- *
- * This function uses kzalloc(), so the caller must call kfree()
- * if this function didn't return NULL.
- */
-static const char *tomoyo_get_exe(void)
+static s8 tomoyo_find_yesno(const char *string, const char *find)
 {
-       struct mm_struct *mm = current->mm;
-       struct vm_area_struct *vma;
-       const char *cp = NULL;
-
-       if (!mm)
-               return NULL;
-       down_read(&mm->mmap_sem);
-       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
-                       cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
-                       break;
-               }
+       const char *cp = strstr(string, find);
+       if (cp) {
+               cp += strlen(find);
+               if (!strncmp(cp, "=yes", 4))
+                       return 1;
+               else if (!strncmp(cp, "=no", 3))
+                       return 0;
        }
-       up_read(&mm->mmap_sem);
-       return cp;
+       return -1;
 }
 
-/**
- * tomoyo_get_msg - Get warning message.
- *
- * @is_enforce: Is it enforcing mode?
- *
- * Returns "ERROR" or "WARNING".
- */
-const char *tomoyo_get_msg(const bool is_enforce)
+static void tomoyo_set_bool(bool *b, const char *string, const char *find)
 {
-       if (is_enforce)
-               return "ERROR";
-       else
-               return "WARNING";
+       switch (tomoyo_find_yesno(string, find)) {
+       case 1:
+               *b = true;
+               break;
+       case 0:
+               *b = false;
+               break;
+       }
 }
 
-/**
- * tomoyo_check_flags - Check mode for specified functionality.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @index:  The functionality to check mode.
- *
- * TOMOYO checks only process context.
- * This code disables TOMOYO's enforcement in case the function is called from
- * interrupt context.
- */
-unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
-                               const u8 index)
+static void tomoyo_set_uint(unsigned int *i, const char *string,
+                           const char *find)
 {
-       const u8 profile = domain->profile;
-
-       if (WARN_ON(in_interrupt()))
-               return 0;
-       return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
-#if TOMOYO_MAX_PROFILES != 256
-               && profile < TOMOYO_MAX_PROFILES
-#endif
-               && tomoyo_profile_ptr[profile] ?
-               tomoyo_profile_ptr[profile]->value[index] : 0;
-}
-
-/**
- * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if domain policy violation warning should be printed to
- * console.
- */
-bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
-{
-       return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
+       const char *cp = strstr(string, find);
+       if (cp)
+               sscanf(cp + strlen(find), "=%u", i);
 }
 
-/**
- * tomoyo_domain_quota_is_ok - Check for domain's quota.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if the domain is not exceeded quota, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
+static void tomoyo_set_pref(const char *name, const char *value,
+                           const bool use_default,
+                           struct tomoyo_profile *profile)
 {
-       unsigned int count = 0;
-       struct tomoyo_acl_info *ptr;
-
-       if (!domain)
-               return true;
-       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-               switch (ptr->type) {
-                       struct tomoyo_path_acl *acl;
-                       u32 perm;
-                       u8 i;
-               case TOMOYO_TYPE_PATH_ACL:
-                       acl = container_of(ptr, struct tomoyo_path_acl, head);
-                       perm = acl->perm | (((u32) acl->perm_high) << 16);
-                       for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
-                               if (perm & (1 << i))
-                                       count++;
-                       if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
-                               count -= 2;
-                       break;
-               case TOMOYO_TYPE_PATH2_ACL:
-                       perm = container_of(ptr, struct tomoyo_path2_acl, head)
-                               ->perm;
-                       for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
-                               if (perm & (1 << i))
-                                       count++;
-                       break;
+       struct tomoyo_preference **pref;
+       bool *verbose;
+       if (!strcmp(name, "enforcing")) {
+               if (use_default) {
+                       pref = &profile->enforcing;
+                       goto set_default;
                }
+               profile->enforcing = &profile->preference;
+               verbose = &profile->preference.enforcing_verbose;
+               goto set_verbose;
        }
-       if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
-               return true;
-       if (!domain->quota_warned) {
-               domain->quota_warned = true;
-               printk(KERN_WARNING "TOMOYO-WARNING: "
-                      "Domain '%s' has so many ACLs to hold. "
-                      "Stopped learning mode.\n", domain->domainname->name);
+       if (!strcmp(name, "permissive")) {
+               if (use_default) {
+                       pref = &profile->permissive;
+                       goto set_default;
+               }
+               profile->permissive = &profile->preference;
+               verbose = &profile->preference.permissive_verbose;
+               goto set_verbose;
        }
-       return false;
+       if (!strcmp(name, "learning")) {
+               if (use_default) {
+                       pref = &profile->learning;
+                       goto set_default;
+               }
+               profile->learning = &profile->preference;
+               tomoyo_set_uint(&profile->preference.learning_max_entry, value,
+                            "max_entry");
+               verbose = &profile->preference.learning_verbose;
+               goto set_verbose;
+       }
+       return;
+ set_default:
+       *pref = &tomoyo_default_profile.preference;
+       return;
+ set_verbose:
+       tomoyo_set_bool(verbose, value, "verbose");
 }
 
-/**
- * tomoyo_find_or_assign_new_profile - Create a new profile.
- *
- * @profile: Profile number to create.
- *
- * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
- */
-static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
-                                                               int profile)
+static int tomoyo_set_mode(char *name, const char *value,
+                          const bool use_default,
+                          struct tomoyo_profile *profile)
 {
-       struct tomoyo_profile *ptr = NULL;
-       int i;
-
-       if (profile >= TOMOYO_MAX_PROFILES)
-               return NULL;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               return NULL;
-       ptr = tomoyo_profile_ptr[profile];
-       if (ptr)
-               goto ok;
-       ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
-       if (!tomoyo_memory_ok(ptr)) {
-               kfree(ptr);
-               ptr = NULL;
-               goto ok;
+       u8 i;
+       u8 config;
+       if (!strcmp(name, "CONFIG")) {
+               i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
+               config = profile->default_config;
+       } else if (tomoyo_str_starts(&name, "CONFIG::")) {
+               config = 0;
+               for (i = 0; i < TOMOYO_MAX_MAC_INDEX
+                            + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+                       if (strcmp(name, tomoyo_mac_keywords[i]))
+                               continue;
+                       config = profile->config[i];
+                       break;
+               }
+               if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+                       return -EINVAL;
+       } else {
+               return -EINVAL;
        }
-       for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
-               ptr->value[i] = tomoyo_control_array[i].current_value;
-       mb(); /* Avoid out-of-order execution. */
-       tomoyo_profile_ptr[profile] = ptr;
- ok:
-       mutex_unlock(&tomoyo_policy_lock);
-       return ptr;
+       if (use_default) {
+               config = TOMOYO_CONFIG_USE_DEFAULT;
+       } else {
+               u8 mode;
+               for (mode = 0; mode < 4; mode++)
+                       if (strstr(value, tomoyo_mode[mode]))
+                               /*
+                                * Update lower 3 bits in order to distinguish
+                                * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
+                                */
+                               config = (config & ~7) | mode;
+       }
+       if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+               profile->config[i] = config;
+       else if (config != TOMOYO_CONFIG_USE_DEFAULT)
+               profile->default_config = config;
+       return 0;
 }
 
 /**
- * tomoyo_write_profile - Write to profile table.
+ * tomoyo_write_profile - Write profile table.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -980,153 +430,165 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
        unsigned int i;
-       unsigned int value;
+       bool use_default = false;
        char *cp;
        struct tomoyo_profile *profile;
-       unsigned long num;
-
-       cp = strchr(data, '-');
-       if (cp)
-               *cp = '\0';
-       if (strict_strtoul(data, 10, &num))
-               return -EINVAL;
-       if (cp)
+       if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+               return 0;
+       i = simple_strtoul(data, &cp, 10);
+       if (data == cp) {
+               profile = &tomoyo_default_profile;
+       } else {
+               if (*cp != '-')
+                       return -EINVAL;
                data = cp + 1;
-       profile = tomoyo_find_or_assign_new_profile(num);
-       if (!profile)
-               return -EINVAL;
+               profile = tomoyo_assign_profile(i);
+               if (!profile)
+                       return -EINVAL;
+       }
        cp = strchr(data, '=');
        if (!cp)
                return -EINVAL;
-       *cp = '\0';
+       *cp++ = '\0';
+       if (profile != &tomoyo_default_profile)
+               use_default = strstr(cp, "use_default") != NULL;
+       if (tomoyo_str_starts(&data, "PREFERENCE::")) {
+               tomoyo_set_pref(data, cp, use_default, profile);
+               return 0;
+       }
+       if (profile == &tomoyo_default_profile)
+               return -EINVAL;
        if (!strcmp(data, "COMMENT")) {
                const struct tomoyo_path_info *old_comment = profile->comment;
-               profile->comment = tomoyo_get_name(cp + 1);
+               profile->comment = tomoyo_get_name(cp);
                tomoyo_put_name(old_comment);
                return 0;
        }
-       for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
-               if (strcmp(data, tomoyo_control_array[i].keyword))
-                       continue;
-               if (sscanf(cp + 1, "%u", &value) != 1) {
-                       int j;
-                       const char **modes;
-                       switch (i) {
-                       case TOMOYO_VERBOSE:
-                               modes = tomoyo_mode_2;
-                               break;
-                       default:
-                               modes = tomoyo_mode_4;
-                               break;
-                       }
-                       for (j = 0; j < 4; j++) {
-                               if (strcmp(cp + 1, modes[j]))
-                                       continue;
-                               value = j;
-                               break;
-                       }
-                       if (j == 4)
-                               return -EINVAL;
-               } else if (value > tomoyo_control_array[i].max_value) {
-                       value = tomoyo_control_array[i].max_value;
-               }
-               profile->value[i] = value;
-               return 0;
+       return tomoyo_set_mode(data, cp, use_default, profile);
+}
+
+static void tomoyo_print_preference(struct tomoyo_io_buffer *head,
+                                   const int idx)
+{
+       struct tomoyo_preference *pref = &tomoyo_default_profile.preference;
+       const struct tomoyo_profile *profile = idx >= 0 ?
+               tomoyo_profile_ptr[idx] : NULL;
+       char buffer[16] = "";
+       if (profile) {
+               buffer[sizeof(buffer) - 1] = '\0';
+               snprintf(buffer, sizeof(buffer) - 1, "%u-", idx);
        }
-       return -EINVAL;
+       if (profile) {
+               pref = profile->learning;
+               if (pref == &tomoyo_default_profile.preference)
+                       goto skip1;
+       }
+       tomoyo_io_printf(head, "%sPREFERENCE::%s={ "
+                        "verbose=%s max_entry=%u }\n",
+                        buffer, "learning",
+                        tomoyo_yesno(pref->learning_verbose),
+                        pref->learning_max_entry);
+ skip1:
+       if (profile) {
+               pref = profile->permissive;
+               if (pref == &tomoyo_default_profile.preference)
+                       goto skip2;
+       }
+       tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
+                        buffer, "permissive",
+                        tomoyo_yesno(pref->permissive_verbose));
+ skip2:
+       if (profile) {
+               pref = profile->enforcing;
+               if (pref == &tomoyo_default_profile.preference)
+                       return;
+       }
+       tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
+                        buffer, "enforcing",
+                        tomoyo_yesno(pref->enforcing_verbose));
+}
+
+static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
+{
+       tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]);
 }
 
 /**
- * tomoyo_read_profile - Read from profile table.
+ * tomoyo_read_profile - Read profile table.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
  */
-static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
+static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
 {
-       static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
-       int step;
-
-       if (head->read_eof)
-               return 0;
-       for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
-            step++) {
-               const u8 index = step / total;
-               u8 type = step % total;
-               const struct tomoyo_profile *profile
-                       = tomoyo_profile_ptr[index];
-               head->read_step = step;
-               if (!profile)
-                       continue;
-               if (!type) { /* Print profile' comment tag. */
-                       if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
-                                             index, profile->comment ?
-                                             profile->comment->name : ""))
+       u8 index;
+       const struct tomoyo_profile *profile;
+ next:
+       index = head->r.index;
+       profile = tomoyo_profile_ptr[index];
+       switch (head->r.step) {
+       case 0:
+               tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");
+               tomoyo_print_preference(head, -1);
+               head->r.step++;
+               break;
+       case 1:
+               for ( ; head->r.index < TOMOYO_MAX_PROFILES;
+                     head->r.index++)
+                       if (tomoyo_profile_ptr[head->r.index])
                                break;
-                       continue;
+               if (head->r.index == TOMOYO_MAX_PROFILES)
+                       return;
+               head->r.step++;
+               break;
+       case 2:
+               {
+                       const struct tomoyo_path_info *comment =
+                               profile->comment;
+                       tomoyo_io_printf(head, "%u-COMMENT=", index);
+                       tomoyo_set_string(head, comment ? comment->name : "");
+                       tomoyo_set_lf(head);
+                       head->r.step++;
                }
-               type--;
-               if (type < TOMOYO_MAX_CONTROL_INDEX) {
-                       const unsigned int value = profile->value[type];
-                       const char **modes = NULL;
-                       const char *keyword
-                               = tomoyo_control_array[type].keyword;
-                       switch (tomoyo_control_array[type].max_value) {
-                       case 3:
-                               modes = tomoyo_mode_4;
-                               break;
-                       case 1:
-                               modes = tomoyo_mode_2;
-                               break;
-                       }
-                       if (modes) {
-                               if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
-                                                     keyword, modes[value]))
-                                       break;
-                       } else {
-                               if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
-                                                     keyword, value))
-                                       break;
-                       }
+               break;
+       case 3:
+               {
+                       tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
+                       tomoyo_print_config(head, profile->default_config);
+                       head->r.bit = 0;
+                       head->r.step++;
+               }
+               break;
+       case 4:
+               for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
+                             + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
+                       const u8 i = head->r.bit;
+                       const u8 config = profile->config[i];
+                       if (config == TOMOYO_CONFIG_USE_DEFAULT)
+                               continue;
+                       tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::",
+                                        tomoyo_mac_keywords[i]);
+                       tomoyo_print_config(head, config);
+                       head->r.bit++;
+                       break;
+               }
+               if (head->r.bit == TOMOYO_MAX_MAC_INDEX
+                   + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
+                       tomoyo_print_preference(head, index);
+                       head->r.index++;
+                       head->r.step = 1;
                }
+               break;
        }
-       if (step == TOMOYO_MAX_PROFILES * total)
-               head->read_eof = true;
-       return 0;
+       if (tomoyo_flush(head))
+               goto next;
 }
 
-/*
- * tomoyo_policy_manager_list is used for holding list of domainnames or
- * programs which are permitted to modify configuration via
- * /sys/kernel/security/tomoyo/ interface.
- *
- * An entry is added by
- *
- * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *  (if you want to specify by a domainname)
- *
- *  or
- *
- * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager
- *  (if you want to specify by a program's location)
- *
- * and is deleted by
- *
- * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *
- *  or
- *
- * # echo 'delete /usr/lib/ccs/editpolicy' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/manager
- */
-LIST_HEAD(tomoyo_policy_manager_list);
+static bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
+                               const struct tomoyo_acl_head *b)
+{
+       return container_of(a, struct tomoyo_manager, head)->manager ==
+               container_of(b, struct tomoyo_manager, head)->manager;
+}
 
 /**
  * tomoyo_update_manager_entry - Add a manager entry.
@@ -1141,47 +603,29 @@ LIST_HEAD(tomoyo_policy_manager_list);
 static int tomoyo_update_manager_entry(const char *manager,
                                       const bool is_delete)
 {
-       struct tomoyo_policy_manager_entry *ptr;
-       struct tomoyo_policy_manager_entry e = { };
-       int error = is_delete ? -ENOENT : -ENOMEM;
+       struct tomoyo_manager e = { };
+       int error;
 
-       if (tomoyo_is_domain_def(manager)) {
-               if (!tomoyo_is_correct_domain(manager))
+       if (tomoyo_domain_def(manager)) {
+               if (!tomoyo_correct_domain(manager))
                        return -EINVAL;
                e.is_domain = true;
        } else {
-               if (!tomoyo_is_correct_path(manager, 1, -1, -1))
+               if (!tomoyo_correct_path(manager))
                        return -EINVAL;
        }
        e.manager = tomoyo_get_name(manager);
        if (!e.manager)
                return -ENOMEM;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
-               if (ptr->manager != e.manager)
-                       continue;
-               ptr->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_policy_manager_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list,
-                                         &tomoyo_policy_manager_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
- out:
+       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                    &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+                                    tomoyo_same_manager);
        tomoyo_put_name(e.manager);
        return error;
 }
 
 /**
- * tomoyo_write_manager_policy - Write manager policy.
+ * tomoyo_write_manager - Write manager policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -1189,7 +633,7 @@ static int tomoyo_update_manager_entry(const char *manager,
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
        bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
@@ -1202,47 +646,41 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
 }
 
 /**
- * tomoyo_read_manager_policy - Read manager policy.
+ * tomoyo_read_manager - Read manager policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns 0.
- *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
 {
-       struct list_head *pos;
-       bool done = true;
-
-       if (head->read_eof)
-               return 0;
-       list_for_each_cookie(pos, head->read_var2,
-                            &tomoyo_policy_manager_list) {
-               struct tomoyo_policy_manager_entry *ptr;
-               ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
-                                list);
-               if (ptr->is_deleted)
+       if (head->r.eof)
+               return;
+       list_for_each_cookie(head->r.acl,
+                            &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+               struct tomoyo_manager *ptr =
+                       list_entry(head->r.acl, typeof(*ptr), head.list);
+               if (ptr->head.is_deleted)
                        continue;
-               done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
-               if (!done)
-                       break;
+               if (!tomoyo_flush(head))
+                       return;
+               tomoyo_set_string(head, ptr->manager->name);
+               tomoyo_set_lf(head);
        }
-       head->read_eof = done;
-       return 0;
+       head->r.eof = true;
 }
 
 /**
- * tomoyo_is_policy_manager - Check whether the current process is a policy manager.
+ * tomoyo_manager - Check whether the current process is a policy manager.
  *
  * Returns true if the current process is permitted to modify policy
  * via /sys/kernel/security/tomoyo/ interface.
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_policy_manager(void)
+static bool tomoyo_manager(void)
 {
-       struct tomoyo_policy_manager_entry *ptr;
+       struct tomoyo_manager *ptr;
        const char *exe;
        const struct task_struct *task = current;
        const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
@@ -1252,8 +690,9 @@ static bool tomoyo_is_policy_manager(void)
                return true;
        if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
-               if (!ptr->is_deleted && ptr->is_domain
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+                               head.list) {
+               if (!ptr->head.is_deleted && ptr->is_domain
                    && !tomoyo_pathcmp(domainname, ptr->manager)) {
                        found = true;
                        break;
@@ -1264,8 +703,9 @@ static bool tomoyo_is_policy_manager(void)
        exe = tomoyo_get_exe();
        if (!exe)
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
-               if (!ptr->is_deleted && !ptr->is_domain
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+                               head.list) {
+               if (!ptr->head.is_deleted && !ptr->is_domain
                    && !strcmp(exe, ptr->manager->name)) {
                        found = true;
                        break;
@@ -1285,7 +725,7 @@ static bool tomoyo_is_policy_manager(void)
 }
 
 /**
- * tomoyo_is_select_one - Parse select command.
+ * tomoyo_select_one - Parse select command.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  * @data: String to parse.
@@ -1294,23 +734,31 @@ static bool tomoyo_is_policy_manager(void)
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
-                                const char *data)
+static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
 {
        unsigned int pid;
        struct tomoyo_domain_info *domain = NULL;
+       bool global_pid = false;
 
-       if (sscanf(data, "pid=%u", &pid) == 1) {
+       if (!strcmp(data, "allow_execute")) {
+               head->r.print_execute_only = true;
+               return true;
+       }
+       if (sscanf(data, "pid=%u", &pid) == 1 ||
+           (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
                struct task_struct *p;
                rcu_read_lock();
                read_lock(&tasklist_lock);
-               p = find_task_by_vpid(pid);
+               if (global_pid)
+                       p = find_task_by_pid_ns(pid, &init_pid_ns);
+               else
+                       p = find_task_by_vpid(pid);
                if (p)
                        domain = tomoyo_real_domain(p);
                read_unlock(&tasklist_lock);
                rcu_read_unlock();
        } else if (!strncmp(data, "domain=", 7)) {
-               if (tomoyo_is_domain_def(data + 7))
+               if (tomoyo_domain_def(data + 7))
                        domain = tomoyo_find_domain(data + 7);
        } else
                return false;
@@ -1318,24 +766,13 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
        /* Accessing read_buf is safe because head->io_sem is held. */
        if (!head->read_buf)
                return true; /* Do nothing if open(O_WRONLY). */
-       head->read_avail = 0;
+       memset(&head->r, 0, sizeof(head->r));
+       head->r.print_this_domain_only = true;
+       head->r.eof = !domain;
+       head->r.domain = &domain->list;
        tomoyo_io_printf(head, "# select %s\n", data);
-       head->read_single_domain = true;
-       head->read_eof = !domain;
-       if (domain) {
-               struct tomoyo_domain_info *d;
-               head->read_var1 = NULL;
-               list_for_each_entry_rcu(d, &tomoyo_domain_list, list) {
-                       if (d == domain)
-                               break;
-                       head->read_var1 = &d->list;
-               }
-               head->read_var2 = NULL;
-               head->read_bit = 0;
-               head->read_step = 0;
-               if (domain->is_deleted)
-                       tomoyo_io_printf(head, "# This is a deleted domain.\n");
-       }
+       if (domain && domain->is_deleted)
+               tomoyo_io_printf(head, "# This is a deleted domain.\n");
        return true;
 }
 
@@ -1373,7 +810,24 @@ static int tomoyo_delete_domain(char *domainname)
 }
 
 /**
- * tomoyo_write_domain_policy - Write domain policy.
+ * tomoyo_write_domain2 - Write domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain,
+                               const bool is_delete)
+{
+       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT))
+               return tomoyo_write_mount(data, domain, is_delete);
+       return tomoyo_write_file(data, domain, is_delete);
+}
+
+/**
+ * tomoyo_write_domain - Write domain policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -1381,7 +835,7 @@ static int tomoyo_delete_domain(char *domainname)
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
        struct tomoyo_domain_info *domain = head->write_var1;
@@ -1393,19 +847,19 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
                is_delete = true;
        else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
                is_select = true;
-       if (is_select && tomoyo_is_select_one(head, data))
+       if (is_select && tomoyo_select_one(head, data))
                return 0;
        /* Don't allow updating policies by non manager programs. */
-       if (!tomoyo_is_policy_manager())
+       if (!tomoyo_manager())
                return -EPERM;
-       if (tomoyo_is_domain_def(data)) {
+       if (tomoyo_domain_def(data)) {
                domain = NULL;
                if (is_delete)
                        tomoyo_delete_domain(data);
                else if (is_select)
                        domain = tomoyo_find_domain(data);
                else
-                       domain = tomoyo_find_or_assign_new_domain(data, 0);
+                       domain = tomoyo_assign_domain(data, 0);
                head->write_var1 = domain;
                return 0;
        }
@@ -1422,179 +876,198 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
                domain->ignore_global_allow_read = !is_delete;
                return 0;
        }
-       return tomoyo_write_file_policy(data, domain, is_delete);
+       if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) {
+               domain->quota_warned = !is_delete;
+               return 0;
+       }
+       if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) {
+               domain->transition_failed = !is_delete;
+               return 0;
+       }
+       return tomoyo_write_domain2(data, domain, is_delete);
 }
 
 /**
- * tomoyo_print_path_acl - Print a single path ACL entry.
+ * tomoyo_fns - Find next set bit.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to "struct tomoyo_path_acl".
+ * @perm: 8 bits value.
+ * @bit:  First bit to find.
  *
- * Returns true on success, false otherwise.
+ * Returns next on-bit on success, 8 otherwise.
  */
-static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
-                                 struct tomoyo_path_acl *ptr)
+static u8 tomoyo_fns(const u8 perm, u8 bit)
 {
-       int pos;
-       u8 bit;
-       const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16);
-
-       for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
-               if (!(perm & (1 << bit)))
-                       continue;
-               /* Print "read/write" instead of "read" and "write". */
-               if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
-                   && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-                       continue;
-               pos = head->read_avail;
-               if (!tomoyo_io_printf(head, "allow_%s ",
-                                     tomoyo_path2keyword(bit)) ||
-                   !tomoyo_print_name_union(head, &ptr->name) ||
-                   !tomoyo_io_printf(head, "\n"))
-                       goto out;
-       }
-       head->read_bit = 0;
-       return true;
- out:
-       head->read_bit = bit;
-       head->read_avail = pos;
-       return false;
+       for ( ; bit < 8; bit++)
+               if (perm & (1 << bit))
+                       break;
+       return bit;
 }
 
 /**
- * tomoyo_print_path2_acl - Print a double path ACL entry.
+ * tomoyo_print_entry - Print an ACL entry.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to "struct tomoyo_path2_acl".
+ * @acl:  Pointer to an ACL entry.
  *
  * Returns true on success, false otherwise.
  */
-static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
-                                  struct tomoyo_path2_acl *ptr)
+static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
+                              struct tomoyo_acl_info *acl)
 {
-       int pos;
-       const u8 perm = ptr->perm;
+       const u8 acl_type = acl->type;
        u8 bit;
 
-       for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
-               if (!(perm & (1 << bit)))
-                       continue;
-               pos = head->read_avail;
-               if (!tomoyo_io_printf(head, "allow_%s ",
-                                     tomoyo_path22keyword(bit)) ||
-                   !tomoyo_print_name_union(head, &ptr->name1) ||
-                   !tomoyo_print_name_union(head, &ptr->name2) ||
-                   !tomoyo_io_printf(head, "\n"))
-                       goto out;
+       if (acl->is_deleted)
+               return true;
+ next:
+       bit = head->r.bit;
+       if (!tomoyo_flush(head))
+               return false;
+       else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
+               struct tomoyo_path_acl *ptr =
+                       container_of(acl, typeof(*ptr), head);
+               const u16 perm = ptr->perm;
+               for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
+                       if (!(perm & (1 << bit)))
+                               continue;
+                       if (head->r.print_execute_only &&
+                           bit != TOMOYO_TYPE_EXECUTE)
+                               continue;
+                       /* Print "read/write" instead of "read" and "write". */
+                       if ((bit == TOMOYO_TYPE_READ ||
+                            bit == TOMOYO_TYPE_WRITE)
+                           && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+                               continue;
+                       break;
+               }
+               if (bit >= TOMOYO_MAX_PATH_OPERATION)
+                       goto done;
+               tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]);
+               tomoyo_print_name_union(head, &ptr->name);
+       } else if (head->r.print_execute_only) {
+               return true;
+       } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
+               struct tomoyo_path2_acl *ptr =
+                       container_of(acl, typeof(*ptr), head);
+               bit = tomoyo_fns(ptr->perm, bit);
+               if (bit >= TOMOYO_MAX_PATH2_OPERATION)
+                       goto done;
+               tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]);
+               tomoyo_print_name_union(head, &ptr->name1);
+               tomoyo_print_name_union(head, &ptr->name2);
+       } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
+               struct tomoyo_path_number_acl *ptr =
+                       container_of(acl, typeof(*ptr), head);
+               bit = tomoyo_fns(ptr->perm, bit);
+               if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION)
+                       goto done;
+               tomoyo_io_printf(head, "allow_%s",
+                                tomoyo_path_number_keyword[bit]);
+               tomoyo_print_name_union(head, &ptr->name);
+               tomoyo_print_number_union(head, &ptr->number);
+       } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
+               struct tomoyo_mkdev_acl *ptr =
+                       container_of(acl, typeof(*ptr), head);
+               bit = tomoyo_fns(ptr->perm, bit);
+               if (bit >= TOMOYO_MAX_MKDEV_OPERATION)
+                       goto done;
+               tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]);
+               tomoyo_print_name_union(head, &ptr->name);
+               tomoyo_print_number_union(head, &ptr->mode);
+               tomoyo_print_number_union(head, &ptr->major);
+               tomoyo_print_number_union(head, &ptr->minor);
+       } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
+               struct tomoyo_mount_acl *ptr =
+                       container_of(acl, typeof(*ptr), head);
+               tomoyo_io_printf(head, "allow_mount");
+               tomoyo_print_name_union(head, &ptr->dev_name);
+               tomoyo_print_name_union(head, &ptr->dir_name);
+               tomoyo_print_name_union(head, &ptr->fs_type);
+               tomoyo_print_number_union(head, &ptr->flags);
        }
-       head->read_bit = 0;
+       head->r.bit = bit + 1;
+       tomoyo_io_printf(head, "\n");
+       if (acl_type != TOMOYO_TYPE_MOUNT_ACL)
+               goto next;
+ done:
+       head->r.bit = 0;
        return true;
- out:
-       head->read_bit = bit;
-       head->read_avail = pos;
-       return false;
 }
 
 /**
- * tomoyo_print_entry - Print an ACL entry.
+ * tomoyo_read_domain2 - Read domain policy.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to an ACL entry.
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ *
+ * Caller holds tomoyo_read_lock().
  *
  * Returns true on success, false otherwise.
  */
-static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
-                              struct tomoyo_acl_info *ptr)
+static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
+                               struct tomoyo_domain_info *domain)
 {
-       const u8 acl_type = ptr->type;
-
-       if (acl_type == TOMOYO_TYPE_PATH_ACL) {
-               struct tomoyo_path_acl *acl
-                       = container_of(ptr, struct tomoyo_path_acl, head);
-               return tomoyo_print_path_acl(head, acl);
-       }
-       if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
-               struct tomoyo_path2_acl *acl
-                       = container_of(ptr, struct tomoyo_path2_acl, head);
-               return tomoyo_print_path2_acl(head, acl);
+       list_for_each_cookie(head->r.acl, &domain->acl_info_list) {
+               struct tomoyo_acl_info *ptr =
+                       list_entry(head->r.acl, typeof(*ptr), list);
+               if (!tomoyo_print_entry(head, ptr))
+                       return false;
        }
-       BUG(); /* This must not happen. */
-       return false;
+       head->r.acl = NULL;
+       return true;
 }
 
 /**
- * tomoyo_read_domain_policy - Read domain policy.
+ * tomoyo_read_domain - Read domain policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns 0.
- *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
 {
-       struct list_head *dpos;
-       struct list_head *apos;
-       bool done = true;
-
-       if (head->read_eof)
-               return 0;
-       if (head->read_step == 0)
-               head->read_step = 1;
-       list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
-               struct tomoyo_domain_info *domain;
-               const char *quota_exceeded = "";
-               const char *transition_failed = "";
-               const char *ignore_global_allow_read = "";
-               domain = list_entry(dpos, struct tomoyo_domain_info, list);
-               if (head->read_step != 1)
-                       goto acl_loop;
-               if (domain->is_deleted && !head->read_single_domain)
-                       continue;
-               /* Print domainname and flags. */
-               if (domain->quota_warned)
-                       quota_exceeded = "quota_exceeded\n";
-               if (domain->transition_failed)
-                       transition_failed = "transition_failed\n";
-               if (domain->ignore_global_allow_read)
-                       ignore_global_allow_read
-                               = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
-               done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
-                                       "%u\n%s%s%s\n",
-                                       domain->domainname->name,
-                                       domain->profile, quota_exceeded,
-                                       transition_failed,
-                                       ignore_global_allow_read);
-               if (!done)
-                       break;
-               head->read_step = 2;
-acl_loop:
-               if (head->read_step == 3)
-                       goto tail_mark;
-               /* Print ACL entries in the domain. */
-               list_for_each_cookie(apos, head->read_var2,
-                                    &domain->acl_info_list) {
-                       struct tomoyo_acl_info *ptr
-                               = list_entry(apos, struct tomoyo_acl_info,
-                                            list);
-                       done = tomoyo_print_entry(head, ptr);
-                       if (!done)
-                               break;
+       if (head->r.eof)
+               return;
+       list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+               struct tomoyo_domain_info *domain =
+                       list_entry(head->r.domain, typeof(*domain), list);
+               switch (head->r.step) {
+               case 0:
+                       if (domain->is_deleted &&
+                           !head->r.print_this_domain_only)
+                               continue;
+                       /* Print domainname and flags. */
+                       tomoyo_set_string(head, domain->domainname->name);
+                       tomoyo_set_lf(head);
+                       tomoyo_io_printf(head,
+                                        TOMOYO_KEYWORD_USE_PROFILE "%u\n",
+                                        domain->profile);
+                       if (domain->quota_warned)
+                               tomoyo_set_string(head, "quota_exceeded\n");
+                       if (domain->transition_failed)
+                               tomoyo_set_string(head, "transition_failed\n");
+                       if (domain->ignore_global_allow_read)
+                               tomoyo_set_string(head,
+                                      TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ
+                                                 "\n");
+                       head->r.step++;
+                       tomoyo_set_lf(head);
+                       /* fall through */
+               case 1:
+                       if (!tomoyo_read_domain2(head, domain))
+                               return;
+                       head->r.step++;
+                       if (!tomoyo_set_lf(head))
+                               return;
+                       /* fall through */
+               case 2:
+                       head->r.step = 0;
+                       if (head->r.print_this_domain_only)
+                               goto done;
                }
-               if (!done)
-                       break;
-               head->read_step = 3;
-tail_mark:
-               done = tomoyo_io_printf(head, "\n");
-               if (!done)
-                       break;
-               head->read_step = 1;
-               if (head->read_single_domain)
-                       break;
        }
-       head->read_eof = done;
-       return 0;
+ done:
+       head->r.eof = true;
 }
 
 /**
@@ -1607,7 +1080,7 @@ tail_mark:
  * This is equivalent to doing
  *
  *     ( echo "select " $domainname; echo "use_profile " $profile ) |
- *     /usr/lib/ccs/loadpolicy -d
+ *     /usr/sbin/tomoyo-loadpolicy -d
  *
  * Caller holds tomoyo_read_lock().
  */
@@ -1631,279 +1104,637 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
 }
 
 /**
- * tomoyo_read_domain_profile - Read only domainname and profile.
+ * tomoyo_read_domain_profile - Read only domainname and profile.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns list of profile number and domainname pairs.
+ *
+ * This is equivalent to doing
+ *
+ *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
+ *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
+ *     domainname = $0; } else if ( $1 == "use_profile" ) {
+ *     print $2 " " domainname; domainname = ""; } } ; '
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
+{
+       if (head->r.eof)
+               return;
+       list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+               struct tomoyo_domain_info *domain =
+                       list_entry(head->r.domain, typeof(*domain), list);
+               if (domain->is_deleted)
+                       continue;
+               if (!tomoyo_flush(head))
+                       return;
+               tomoyo_io_printf(head, "%u ", domain->profile);
+               tomoyo_set_string(head, domain->domainname->name);
+               tomoyo_set_lf(head);
+       }
+       head->r.eof = true;
+}
+
+/**
+ * tomoyo_write_pid: Specify PID to obtain domainname.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
+{
+       head->r.eof = false;
+       return 0;
+}
+
+/**
+ * tomoyo_read_pid - Get domainname of the specified PID.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns the domainname which the specified PID is in on success,
+ * empty string otherwise.
+ * The PID is specified by tomoyo_write_pid() so that the user can obtain
+ * using read()/write() interface rather than sysctl() interface.
+ */
+static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
+{
+       char *buf = head->write_buf;
+       bool global_pid = false;
+       unsigned int pid;
+       struct task_struct *p;
+       struct tomoyo_domain_info *domain = NULL;
+
+       /* Accessing write_buf is safe because head->io_sem is held. */
+       if (!buf) {
+               head->r.eof = true;
+               return; /* Do nothing if open(O_RDONLY). */
+       }
+       if (head->r.w_pos || head->r.eof)
+               return;
+       head->r.eof = true;
+       if (tomoyo_str_starts(&buf, "global-pid "))
+               global_pid = true;
+       pid = (unsigned int) simple_strtoul(buf, NULL, 10);
+       rcu_read_lock();
+       read_lock(&tasklist_lock);
+       if (global_pid)
+               p = find_task_by_pid_ns(pid, &init_pid_ns);
+       else
+               p = find_task_by_vpid(pid);
+       if (p)
+               domain = tomoyo_real_domain(p);
+       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
+       if (!domain)
+               return;
+       tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
+       tomoyo_set_string(head, domain->domainname->name);
+}
+
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+       [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
+       = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
+       [TOMOYO_TRANSITION_CONTROL_INITIALIZE]
+       = TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+       [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
+       [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+};
+
+static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
+       [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP,
+       [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP
+};
+
+/**
+ * tomoyo_write_exception - Write exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+       u8 i;
+       static const struct {
+               const char *keyword;
+               int (*write) (char *, const bool);
+       } tomoyo_callback[4] = {
+               { TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator },
+               { TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern },
+               { TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite },
+               { TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable },
+       };
+
+       for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
+               if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
+                       return tomoyo_write_transition_control(data, is_delete,
+                                                              i);
+       for (i = 0; i < 4; i++)
+               if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword))
+                       return tomoyo_callback[i].write(data, is_delete);
+       for (i = 0; i < TOMOYO_MAX_GROUP; i++)
+               if (tomoyo_str_starts(&data, tomoyo_group_name[i]))
+                       return tomoyo_write_group(data, is_delete, i);
+       return -EINVAL;
+}
+
+/**
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx:  Index number.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
+{
+       list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) {
+               struct tomoyo_group *group =
+                       list_entry(head->r.group, typeof(*group), list);
+               list_for_each_cookie(head->r.acl, &group->member_list) {
+                       struct tomoyo_acl_head *ptr =
+                               list_entry(head->r.acl, typeof(*ptr), list);
+                       if (ptr->is_deleted)
+                               continue;
+                       if (!tomoyo_flush(head))
+                               return false;
+                       tomoyo_set_string(head, tomoyo_group_name[idx]);
+                       tomoyo_set_string(head, group->group_name->name);
+                       if (idx == TOMOYO_PATH_GROUP) {
+                               tomoyo_set_space(head);
+                               tomoyo_set_string(head, container_of
+                                              (ptr, struct tomoyo_path_group,
+                                               head)->member_name->name);
+                       } else if (idx == TOMOYO_NUMBER_GROUP) {
+                               tomoyo_print_number_union(head, &container_of
+                                                         (ptr,
+                                                  struct tomoyo_number_group,
+                                                          head)->number);
+                       }
+                       tomoyo_set_lf(head);
+               }
+               head->r.acl = NULL;
+       }
+       head->r.group = NULL;
+       return true;
+}
+
+/**
+ * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx:  Index number.
  *
- * Returns list of profile number and domainname pairs.
- *
- * This is equivalent to doing
- *
- *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
- *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
- *     domainname = $0; } else if ( $1 == "use_profile" ) {
- *     print $2 " " domainname; domainname = ""; } } ; '
+ * Returns true on success, false otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
+static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
 {
-       struct list_head *pos;
-       bool done = true;
-
-       if (head->read_eof)
-               return 0;
-       list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
-               struct tomoyo_domain_info *domain;
-               domain = list_entry(pos, struct tomoyo_domain_info, list);
-               if (domain->is_deleted)
+       list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) {
+               struct tomoyo_acl_head *acl =
+                       container_of(head->r.acl, typeof(*acl), list);
+               if (acl->is_deleted)
                        continue;
-               done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
-                                       domain->domainname->name);
-               if (!done)
+               if (!tomoyo_flush(head))
+                       return false;
+               switch (idx) {
+               case TOMOYO_ID_TRANSITION_CONTROL:
+                       {
+                               struct tomoyo_transition_control *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               tomoyo_set_string(head,
+                                                 tomoyo_transition_type
+                                                 [ptr->type]);
+                               if (ptr->program)
+                                       tomoyo_set_string(head,
+                                                         ptr->program->name);
+                               if (ptr->program && ptr->domainname)
+                                       tomoyo_set_string(head, " from ");
+                               if (ptr->domainname)
+                                       tomoyo_set_string(head,
+                                                         ptr->domainname->
+                                                         name);
+                       }
+                       break;
+               case TOMOYO_ID_GLOBALLY_READABLE:
+                       {
+                               struct tomoyo_readable_file *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               tomoyo_set_string(head,
+                                                 TOMOYO_KEYWORD_ALLOW_READ);
+                               tomoyo_set_string(head, ptr->filename->name);
+                       }
+                       break;
+               case TOMOYO_ID_AGGREGATOR:
+                       {
+                               struct tomoyo_aggregator *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               tomoyo_set_string(head,
+                                                 TOMOYO_KEYWORD_AGGREGATOR);
+                               tomoyo_set_string(head,
+                                                 ptr->original_name->name);
+                               tomoyo_set_space(head);
+                               tomoyo_set_string(head,
+                                              ptr->aggregated_name->name);
+                       }
+                       break;
+               case TOMOYO_ID_PATTERN:
+                       {
+                               struct tomoyo_no_pattern *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               tomoyo_set_string(head,
+                                                 TOMOYO_KEYWORD_FILE_PATTERN);
+                               tomoyo_set_string(head, ptr->pattern->name);
+                       }
+                       break;
+               case TOMOYO_ID_NO_REWRITE:
+                       {
+                               struct tomoyo_no_rewrite *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               tomoyo_set_string(head,
+                                                 TOMOYO_KEYWORD_DENY_REWRITE);
+                               tomoyo_set_string(head, ptr->pattern->name);
+                       }
                        break;
+               default:
+                       continue;
+               }
+               tomoyo_set_lf(head);
        }
-       head->read_eof = done;
-       return 0;
+       head->r.acl = NULL;
+       return true;
 }
 
 /**
- * tomoyo_write_pid: Specify PID to obtain domainname.
+ * tomoyo_read_exception - Read exception policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns 0.
+ * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
+static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
 {
-       unsigned long pid;
-       /* No error check. */
-       strict_strtoul(head->write_buf, 10, &pid);
-       head->read_step = (int) pid;
-       head->read_eof = false;
-       return 0;
+       if (head->r.eof)
+               return;
+       while (head->r.step < TOMOYO_MAX_POLICY &&
+              tomoyo_read_policy(head, head->r.step))
+               head->r.step++;
+       if (head->r.step < TOMOYO_MAX_POLICY)
+               return;
+       while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
+              tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY))
+               head->r.step++;
+       if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
+               return;
+       head->r.eof = true;
 }
 
 /**
- * tomoyo_read_pid - Get domainname of the specified PID.
+ * tomoyo_print_header - Get header line of audit log.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
+ * @r: Pointer to "struct tomoyo_request_info".
  *
- * Returns the domainname which the specified PID is in on success,
- * empty string otherwise.
- * The PID is specified by tomoyo_write_pid() so that the user can obtain
- * using read()/write() interface rather than sysctl() interface.
+ * Returns string representation.
+ *
+ * This function uses kmalloc(), so caller must kfree() if this function
+ * didn't return NULL.
  */
-static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
+static char *tomoyo_print_header(struct tomoyo_request_info *r)
 {
-       if (head->read_avail == 0 && !head->read_eof) {
-               const int pid = head->read_step;
-               struct task_struct *p;
-               struct tomoyo_domain_info *domain = NULL;
-               rcu_read_lock();
-               read_lock(&tasklist_lock);
-               p = find_task_by_vpid(pid);
-               if (p)
-                       domain = tomoyo_real_domain(p);
-               read_unlock(&tasklist_lock);
-               rcu_read_unlock();
-               if (domain)
-                       tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
-                                        domain->domainname->name);
-               head->read_eof = true;
-       }
-       return 0;
+       struct timeval tv;
+       const pid_t gpid = task_pid_nr(current);
+       static const int tomoyo_buffer_len = 4096;
+       char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+       if (!buffer)
+               return NULL;
+       do_gettimeofday(&tv);
+       snprintf(buffer, tomoyo_buffer_len - 1,
+                "#timestamp=%lu profile=%u mode=%s (global-pid=%u)"
+                " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u"
+                " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
+                tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid,
+                (pid_t) sys_getpid(), (pid_t) sys_getppid(),
+                current_uid(), current_gid(), current_euid(),
+                current_egid(), current_suid(), current_sgid(),
+                current_fsuid(), current_fsgid());
+       return buffer;
 }
 
 /**
- * tomoyo_write_exception_policy - Write exception policy.
+ * tomoyo_init_audit_log - Allocate buffer for audit logs.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
+ * @len: Required size.
+ * @r:   Pointer to "struct tomoyo_request_info".
  *
- * Returns 0 on success, negative value otherwise.
+ * Returns pointer to allocated memory.
  *
- * Caller holds tomoyo_read_lock().
+ * The @len is updated to add the header lines' size on success.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
  */
-static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
+static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r)
 {
-       char *data = head->write_buf;
-       bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+       char *buf = NULL;
+       const char *header;
+       const char *domainname;
+       if (!r->domain)
+               r->domain = tomoyo_domain();
+       domainname = r->domain->domainname->name;
+       header = tomoyo_print_header(r);
+       if (!header)
+               return NULL;
+       *len += strlen(domainname) + strlen(header) + 10;
+       buf = kzalloc(*len, GFP_NOFS);
+       if (buf)
+               snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname);
+       kfree(header);
+       return buf;
+}
 
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
-               return tomoyo_write_domain_keeper_policy(data, false,
-                                                        is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
-               return tomoyo_write_domain_keeper_policy(data, true, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
-               return tomoyo_write_domain_initializer_policy(data, false,
-                                                             is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
-               return tomoyo_write_domain_initializer_policy(data, true,
-                                                             is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
-               return tomoyo_write_alias_policy(data, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
-               return tomoyo_write_globally_readable_policy(data, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
-               return tomoyo_write_pattern_policy(data, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
-               return tomoyo_write_no_rewrite_policy(data, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
-               return tomoyo_write_path_group_policy(data, is_delete);
-       return -EINVAL;
+/* Wait queue for tomoyo_query_list. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
+
+/* Lock for manipulating tomoyo_query_list. */
+static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+
+/* Structure for query. */
+struct tomoyo_query {
+       struct list_head list;
+       char *query;
+       int query_len;
+       unsigned int serial;
+       int timer;
+       int answer;
+};
+
+/* The list for "struct tomoyo_query". */
+static LIST_HEAD(tomoyo_query_list);
+
+/*
+ * Number of "struct file" referring /sys/kernel/security/tomoyo/query
+ * interface.
+ */
+static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
+
+/**
+ * tomoyo_supervisor - Ask for the supervisor's decision.
+ *
+ * @r:       Pointer to "struct tomoyo_request_info".
+ * @fmt:     The printf()'s format string, followed by parameters.
+ *
+ * Returns 0 if the supervisor decided to permit the access request which
+ * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
+ * supervisor decided to retry the access request which violated the policy in
+ * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
+ */
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+       va_list args;
+       int error = -EPERM;
+       int pos;
+       int len;
+       static unsigned int tomoyo_serial;
+       struct tomoyo_query *entry = NULL;
+       bool quota_exceeded = false;
+       char *header;
+       switch (r->mode) {
+               char *buffer;
+       case TOMOYO_CONFIG_LEARNING:
+               if (!tomoyo_domain_quota_is_ok(r))
+                       return 0;
+               va_start(args, fmt);
+               len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4;
+               va_end(args);
+               buffer = kmalloc(len, GFP_NOFS);
+               if (!buffer)
+                       return 0;
+               va_start(args, fmt);
+               vsnprintf(buffer, len - 1, fmt, args);
+               va_end(args);
+               tomoyo_normalize_line(buffer);
+               tomoyo_write_domain2(buffer, r->domain, false);
+               kfree(buffer);
+               /* fall through */
+       case TOMOYO_CONFIG_PERMISSIVE:
+               return 0;
+       }
+       if (!r->domain)
+               r->domain = tomoyo_domain();
+       if (!atomic_read(&tomoyo_query_observers))
+               return -EPERM;
+       va_start(args, fmt);
+       len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
+       va_end(args);
+       header = tomoyo_init_audit_log(&len, r);
+       if (!header)
+               goto out;
+       entry = kzalloc(sizeof(*entry), GFP_NOFS);
+       if (!entry)
+               goto out;
+       entry->query = kzalloc(len, GFP_NOFS);
+       if (!entry->query)
+               goto out;
+       len = ksize(entry->query);
+       spin_lock(&tomoyo_query_list_lock);
+       if (tomoyo_quota_for_query && tomoyo_query_memory_size + len +
+           sizeof(*entry) >= tomoyo_quota_for_query) {
+               quota_exceeded = true;
+       } else {
+               tomoyo_query_memory_size += len + sizeof(*entry);
+               entry->serial = tomoyo_serial++;
+       }
+       spin_unlock(&tomoyo_query_list_lock);
+       if (quota_exceeded)
+               goto out;
+       pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s",
+                      entry->serial, r->retry, header);
+       kfree(header);
+       header = NULL;
+       va_start(args, fmt);
+       vsnprintf(entry->query + pos, len - 1 - pos, fmt, args);
+       entry->query_len = strlen(entry->query) + 1;
+       va_end(args);
+       spin_lock(&tomoyo_query_list_lock);
+       list_add_tail(&entry->list, &tomoyo_query_list);
+       spin_unlock(&tomoyo_query_list_lock);
+       /* Give 10 seconds for supervisor's opinion. */
+       for (entry->timer = 0;
+            atomic_read(&tomoyo_query_observers) && entry->timer < 100;
+            entry->timer++) {
+               wake_up(&tomoyo_query_wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ / 10);
+               if (entry->answer)
+                       break;
+       }
+       spin_lock(&tomoyo_query_list_lock);
+       list_del(&entry->list);
+       tomoyo_query_memory_size -= len + sizeof(*entry);
+       spin_unlock(&tomoyo_query_list_lock);
+       switch (entry->answer) {
+       case 3: /* Asked to retry by administrator. */
+               error = TOMOYO_RETRY_REQUEST;
+               r->retry++;
+               break;
+       case 1:
+               /* Granted by administrator. */
+               error = 0;
+               break;
+       case 0:
+               /* Timed out. */
+               break;
+       default:
+               /* Rejected by administrator. */
+               break;
+       }
+ out:
+       if (entry)
+               kfree(entry->query);
+       kfree(entry);
+       kfree(header);
+       return error;
 }
 
 /**
- * tomoyo_read_exception_policy - Read exception policy.
+ * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
  *
- * Returns 0 on success, -EINVAL otherwise.
+ * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
  *
- * Caller holds tomoyo_read_lock().
+ * Waits for access requests which violated policy in enforcing mode.
  */
-static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_poll_query(struct file *file, poll_table *wait)
 {
-       if (!head->read_eof) {
-               switch (head->read_step) {
-               case 0:
-                       head->read_var2 = NULL;
-                       head->read_step = 1;
-               case 1:
-                       if (!tomoyo_read_domain_keeper_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 2;
-               case 2:
-                       if (!tomoyo_read_globally_readable_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 3;
-               case 3:
-                       head->read_var2 = NULL;
-                       head->read_step = 4;
-               case 4:
-                       if (!tomoyo_read_domain_initializer_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 5;
-               case 5:
-                       if (!tomoyo_read_alias_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 6;
-               case 6:
-                       head->read_var2 = NULL;
-                       head->read_step = 7;
-               case 7:
-                       if (!tomoyo_read_file_pattern(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 8;
-               case 8:
-                       if (!tomoyo_read_no_rewrite_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 9;
-               case 9:
-                       if (!tomoyo_read_path_group_policy(head))
-                               break;
-                       head->read_var1 = NULL;
-                       head->read_var2 = NULL;
-                       head->read_step = 10;
-               case 10:
-                       head->read_eof = true;
+       struct list_head *tmp;
+       bool found = false;
+       u8 i;
+       for (i = 0; i < 2; i++) {
+               spin_lock(&tomoyo_query_list_lock);
+               list_for_each(tmp, &tomoyo_query_list) {
+                       struct tomoyo_query *ptr =
+                               list_entry(tmp, typeof(*ptr), list);
+                       if (ptr->answer)
+                               continue;
+                       found = true;
                        break;
-               default:
-                       return -EINVAL;
                }
+               spin_unlock(&tomoyo_query_list_lock);
+               if (found)
+                       return POLLIN | POLLRDNORM;
+               if (i)
+                       break;
+               poll_wait(file, &tomoyo_query_wait, wait);
        }
        return 0;
 }
 
-/* path to policy loader */
-static const char *tomoyo_loader = "/sbin/tomoyo-init";
-
 /**
- * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
  *
- * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ * @head: Pointer to "struct tomoyo_io_buffer".
  */
-static bool tomoyo_policy_loader_exists(void)
+static void tomoyo_read_query(struct tomoyo_io_buffer *head)
 {
-       /*
-        * Don't activate MAC if the policy loader doesn't exist.
-        * If the initrd includes /sbin/init but real-root-dev has not
-        * mounted on / yet, activating MAC will block the system since
-        * policies are not loaded yet.
-        * Thus, let do_execve() call this function everytime.
-        */
-       struct path path;
-
-       if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
-               printk(KERN_INFO "Not activating Mandatory Access Control now "
-                      "since %s doesn't exist.\n", tomoyo_loader);
-               return false;
+       struct list_head *tmp;
+       int pos = 0;
+       int len = 0;
+       char *buf;
+       if (head->r.w_pos)
+               return;
+       if (head->read_buf) {
+               kfree(head->read_buf);
+               head->read_buf = NULL;
+       }
+       spin_lock(&tomoyo_query_list_lock);
+       list_for_each(tmp, &tomoyo_query_list) {
+               struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+               if (ptr->answer)
+                       continue;
+               if (pos++ != head->r.query_index)
+                       continue;
+               len = ptr->query_len;
+               break;
+       }
+       spin_unlock(&tomoyo_query_list_lock);
+       if (!len) {
+               head->r.query_index = 0;
+               return;
+       }
+       buf = kzalloc(len, GFP_NOFS);
+       if (!buf)
+               return;
+       pos = 0;
+       spin_lock(&tomoyo_query_list_lock);
+       list_for_each(tmp, &tomoyo_query_list) {
+               struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+               if (ptr->answer)
+                       continue;
+               if (pos++ != head->r.query_index)
+                       continue;
+               /*
+                * Some query can be skipped because tomoyo_query_list
+                * can change, but I don't care.
+                */
+               if (len == ptr->query_len)
+                       memmove(buf, ptr->query, len);
+               break;
+       }
+       spin_unlock(&tomoyo_query_list_lock);
+       if (buf[0]) {
+               head->read_buf = buf;
+               head->r.w[head->r.w_pos++] = buf;
+               head->r.query_index++;
+       } else {
+               kfree(buf);
        }
-       path_put(&path);
-       return true;
 }
 
 /**
- * tomoyo_load_policy - Run external policy loader to load policy.
+ * tomoyo_write_answer - Write the supervisor's decision.
  *
- * @filename: The program about to start.
- *
- * This function checks whether @filename is /sbin/init , and if so
- * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
- * and then continues invocation of /sbin/init.
- * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
- * writes to /sys/kernel/security/tomoyo/ interfaces.
+ * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns nothing.
+ * Returns 0 on success, -EINVAL otherwise.
  */
-void tomoyo_load_policy(const char *filename)
+static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
 {
-       char *argv[2];
-       char *envp[3];
-
-       if (tomoyo_policy_loaded)
-               return;
-       /*
-        * Check filename is /sbin/init or /sbin/tomoyo-start.
-        * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
-        * be passed.
-        * You can create /sbin/tomoyo-start by
-        * "ln -s /bin/true /sbin/tomoyo-start".
-        */
-       if (strcmp(filename, "/sbin/init") &&
-           strcmp(filename, "/sbin/tomoyo-start"))
-               return;
-       if (!tomoyo_policy_loader_exists())
-               return;
-
-       printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
-              tomoyo_loader);
-       argv[0] = (char *) tomoyo_loader;
-       argv[1] = NULL;
-       envp[0] = "HOME=/";
-       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-       envp[2] = NULL;
-       call_usermodehelper(argv[0], argv, envp, 1);
-
-       printk(KERN_INFO "TOMOYO: 2.2.0   2009/04/01\n");
-       printk(KERN_INFO "Mandatory Access Control activated.\n");
-       tomoyo_policy_loaded = true;
-       { /* Check all profiles currently assigned to domains are defined. */
-               struct tomoyo_domain_info *domain;
-               list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-                       const u8 profile = domain->profile;
-                       if (tomoyo_profile_ptr[profile])
-                               continue;
-                       panic("Profile %u (used by '%s') not defined.\n",
-                             profile, domain->domainname->name);
-               }
+       char *data = head->write_buf;
+       struct list_head *tmp;
+       unsigned int serial;
+       unsigned int answer;
+       spin_lock(&tomoyo_query_list_lock);
+       list_for_each(tmp, &tomoyo_query_list) {
+               struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+               ptr->timer = 0;
        }
+       spin_unlock(&tomoyo_query_list_lock);
+       if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
+               return -EINVAL;
+       spin_lock(&tomoyo_query_list_lock);
+       list_for_each(tmp, &tomoyo_query_list) {
+               struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+               if (ptr->serial != serial)
+                       continue;
+               if (!ptr->answer)
+                       ptr->answer = answer;
+               break;
+       }
+       spin_unlock(&tomoyo_query_list_lock);
+       return 0;
 }
 
 /**
@@ -1913,13 +1744,12 @@ void tomoyo_load_policy(const char *filename)
  *
  * Returns version information.
  */
-static int tomoyo_read_version(struct tomoyo_io_buffer *head)
+static void tomoyo_read_version(struct tomoyo_io_buffer *head)
 {
-       if (!head->read_eof) {
-               tomoyo_io_printf(head, "2.2.0");
-               head->read_eof = true;
+       if (!head->r.eof) {
+               tomoyo_io_printf(head, "2.3.0");
+               head->r.eof = true;
        }
-       return 0;
 }
 
 /**
@@ -1929,18 +1759,17 @@ static int tomoyo_read_version(struct tomoyo_io_buffer *head)
  *
  * Returns the current process's domainname.
  */
-static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
+static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
 {
-       if (!head->read_eof) {
+       if (!head->r.eof) {
                /*
                 * tomoyo_domain()->domainname != NULL
                 * because every process belongs to a domain and
                 * the domain's name cannot be NULL.
                 */
                tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
-               head->read_eof = true;
+               head->r.eof = true;
        }
-       return 0;
 }
 
 /**
@@ -1953,23 +1782,24 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
  *
  * Caller acquires tomoyo_read_lock().
  */
-static int tomoyo_open_control(const u8 type, struct file *file)
+int tomoyo_open_control(const u8 type, struct file *file)
 {
        struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
 
        if (!head)
                return -ENOMEM;
        mutex_init(&head->io_sem);
+       head->type = type;
        switch (type) {
        case TOMOYO_DOMAINPOLICY:
                /* /sys/kernel/security/tomoyo/domain_policy */
-               head->write = tomoyo_write_domain_policy;
-               head->read = tomoyo_read_domain_policy;
+               head->write = tomoyo_write_domain;
+               head->read = tomoyo_read_domain;
                break;
        case TOMOYO_EXCEPTIONPOLICY:
                /* /sys/kernel/security/tomoyo/exception_policy */
-               head->write = tomoyo_write_exception_policy;
-               head->read = tomoyo_read_exception_policy;
+               head->write = tomoyo_write_exception;
+               head->read = tomoyo_read_exception;
                break;
        case TOMOYO_SELFDOMAIN:
                /* /sys/kernel/security/tomoyo/self_domain */
@@ -2001,10 +1831,15 @@ static int tomoyo_open_control(const u8 type, struct file *file)
                head->write = tomoyo_write_profile;
                head->read = tomoyo_read_profile;
                break;
+       case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
+               head->poll = tomoyo_poll_query;
+               head->write = tomoyo_write_answer;
+               head->read = tomoyo_read_query;
+               break;
        case TOMOYO_MANAGER:
                /* /sys/kernel/security/tomoyo/manager */
-               head->write = tomoyo_write_manager_policy;
-               head->read = tomoyo_read_manager_policy;
+               head->write = tomoyo_write_manager;
+               head->read = tomoyo_read_manager;
                break;
        }
        if (!(file->f_mode & FMODE_READ)) {
@@ -2013,7 +1848,9 @@ static int tomoyo_open_control(const u8 type, struct file *file)
                 * for reading.
                 */
                head->read = NULL;
-       } else {
+               head->poll = NULL;
+       } else if (!head->poll) {
+               /* Don't allocate read_buf for poll() access. */
                if (!head->readbuf_size)
                        head->readbuf_size = 4096 * 2;
                head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
@@ -2037,7 +1874,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
                        return -ENOMEM;
                }
        }
-       head->reader_idx = tomoyo_read_lock();
+       if (type != TOMOYO_QUERY)
+               head->reader_idx = tomoyo_read_lock();
        file->private_data = head;
        /*
         * Call the handler now if the file is
@@ -2048,9 +1886,34 @@ static int tomoyo_open_control(const u8 type, struct file *file)
         */
        if (type == TOMOYO_SELFDOMAIN)
                tomoyo_read_control(file, NULL, 0);
+       /*
+        * If the file is /sys/kernel/security/tomoyo/query , increment the
+        * observer counter.
+        * The obserber counter is used by tomoyo_supervisor() to see if
+        * there is some process monitoring /sys/kernel/security/tomoyo/query.
+        */
+       else if (type == TOMOYO_QUERY)
+               atomic_inc(&tomoyo_query_observers);
        return 0;
 }
 
+/**
+ * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Waits for read readiness.
+ * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd .
+ */
+int tomoyo_poll_control(struct file *file, poll_table *wait)
+{
+       struct tomoyo_io_buffer *head = file->private_data;
+       if (!head->poll)
+               return -ENOSYS;
+       return head->poll(file, wait);
+}
+
 /**
  * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
  *
@@ -2062,36 +1925,23 @@ static int tomoyo_open_control(const u8 type, struct file *file)
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_control(struct file *file, char __user *buffer,
-                              const int buffer_len)
+int tomoyo_read_control(struct file *file, char __user *buffer,
+                       const int buffer_len)
 {
-       int len = 0;
+       int len;
        struct tomoyo_io_buffer *head = file->private_data;
-       char *cp;
 
        if (!head->read)
                return -ENOSYS;
        if (mutex_lock_interruptible(&head->io_sem))
                return -EINTR;
-       /* Call the policy handler. */
-       len = head->read(head);
-       if (len < 0)
-               goto out;
-       /* Write to buffer. */
-       len = head->read_avail;
-       if (len > buffer_len)
-               len = buffer_len;
-       if (!len)
-               goto out;
-       /* head->read_buf changes by some functions. */
-       cp = head->read_buf;
-       if (copy_to_user(buffer, cp, len)) {
-               len = -EFAULT;
-               goto out;
-       }
-       head->read_avail -= len;
-       memmove(cp, cp + len, head->read_avail);
- out:
+       head->read_user_buf = buffer;
+       head->read_user_buf_avail = buffer_len;
+       if (tomoyo_flush(head))
+               /* Call the policy handler. */
+               head->read(head);
+       tomoyo_flush(head);
+       len = head->read_user_buf - buffer;
        mutex_unlock(&head->io_sem);
        return len;
 }
@@ -2107,8 +1957,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
-                               const int buffer_len)
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+                        const int buffer_len)
 {
        struct tomoyo_io_buffer *head = file->private_data;
        int error = buffer_len;
@@ -2121,8 +1971,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
                return -EFAULT;
        /* Don't allow updating policies by non manager programs. */
        if (head->write != tomoyo_write_pid &&
-           head->write != tomoyo_write_domain_policy &&
-           !tomoyo_is_policy_manager())
+           head->write != tomoyo_write_domain && !tomoyo_manager())
                return -EPERM;
        if (mutex_lock_interruptible(&head->io_sem))
                return -EINTR;
@@ -2159,12 +2008,19 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
  *
  * Caller looses tomoyo_read_lock().
  */
-static int tomoyo_close_control(struct file *file)
+int tomoyo_close_control(struct file *file)
 {
        struct tomoyo_io_buffer *head = file->private_data;
        const bool is_write = !!head->write_buf;
 
-       tomoyo_read_unlock(head->reader_idx);
+       /*
+        * If the file is /sys/kernel/security/tomoyo/query , decrement the
+        * observer counter.
+        */
+       if (head->type == TOMOYO_QUERY)
+               atomic_dec(&tomoyo_query_observers);
+       else
+               tomoyo_read_unlock(head->reader_idx);
        /* Release memory used for policy I/O. */
        kfree(head->read_buf);
        head->read_buf = NULL;
@@ -2179,129 +2035,25 @@ static int tomoyo_close_control(struct file *file)
 }
 
 /**
- * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file:  Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_open(struct inode *inode, struct file *file)
-{
-       const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
-               - ((u8 *) NULL);
-       return tomoyo_open_control(key, file);
-}
-
-/**
- * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file:  Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_release(struct inode *inode, struct file *file)
-{
-       return tomoyo_close_control(file);
-}
-
-/**
- * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file:  Pointer to "struct file".
- * @buf:   Pointer to buffer.
- * @count: Size of @buf.
- * @ppos:  Unused.
- *
- * Returns bytes read on success, negative value otherwise.
- */
-static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
-                          loff_t *ppos)
-{
-       return tomoyo_read_control(file, buf, count);
-}
-
-/**
- * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file:  Pointer to "struct file".
- * @buf:   Pointer to buffer.
- * @count: Size of @buf.
- * @ppos:  Unused.
- *
- * Returns @count on success, negative value otherwise.
- */
-static ssize_t tomoyo_write(struct file *file, const char __user *buf,
-                           size_t count, loff_t *ppos)
-{
-       return tomoyo_write_control(file, buf, count);
-}
-
-/*
- * tomoyo_operations is a "struct file_operations" which is used for handling
- * /sys/kernel/security/tomoyo/ interface.
- *
- * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
- * See tomoyo_io_buffer for internals.
- */
-static const struct file_operations tomoyo_operations = {
-       .open    = tomoyo_open,
-       .release = tomoyo_release,
-       .read    = tomoyo_read,
-       .write   = tomoyo_write,
-};
-
-/**
- * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
- *
- * @name:   The name of the interface file.
- * @mode:   The permission of the interface file.
- * @parent: The parent directory.
- * @key:    Type of interface.
- *
- * Returns nothing.
- */
-static void __init tomoyo_create_entry(const char *name, const mode_t mode,
-                                      struct dentry *parent, const u8 key)
-{
-       securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
-                              &tomoyo_operations);
-}
-
-/**
- * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
- *
- * Returns 0.
+ * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
  */
-static int __init tomoyo_initerface_init(void)
+void tomoyo_check_profile(void)
 {
-       struct dentry *tomoyo_dir;
-
-       /* Don't create securityfs entries unless registered. */
-       if (current_cred()->security != &tomoyo_kernel_domain)
-               return 0;
-
-       tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
-       tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
-                           TOMOYO_DOMAINPOLICY);
-       tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
-                           TOMOYO_EXCEPTIONPOLICY);
-       tomoyo_create_entry("self_domain",      0400, tomoyo_dir,
-                           TOMOYO_SELFDOMAIN);
-       tomoyo_create_entry(".domain_status",   0600, tomoyo_dir,
-                           TOMOYO_DOMAIN_STATUS);
-       tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
-                           TOMOYO_PROCESS_STATUS);
-       tomoyo_create_entry("meminfo",          0600, tomoyo_dir,
-                           TOMOYO_MEMINFO);
-       tomoyo_create_entry("profile",          0600, tomoyo_dir,
-                           TOMOYO_PROFILE);
-       tomoyo_create_entry("manager",          0600, tomoyo_dir,
-                           TOMOYO_MANAGER);
-       tomoyo_create_entry("version",          0400, tomoyo_dir,
-                           TOMOYO_VERSION);
-       return 0;
+       struct tomoyo_domain_info *domain;
+       const int idx = tomoyo_read_lock();
+       tomoyo_policy_loaded = true;
+       /* Check all profiles currently assigned to domains are defined. */
+       list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+               const u8 profile = domain->profile;
+               if (tomoyo_profile_ptr[profile])
+                       continue;
+               panic("Profile %u (used by '%s') not defined.\n",
+                     profile, domain->domainname->name);
+       }
+       tomoyo_read_unlock(idx);
+       if (tomoyo_profile_version != 20090903)
+               panic("Profile version %u is not supported.\n",
+                     tomoyo_profile_version);
+       printk(KERN_INFO "TOMOYO: 2.3.0\n");
+       printk(KERN_INFO "Mandatory Access Control activated.\n");
 }
-
-fs_initcall(tomoyo_initerface_init);
index 9f1ae5e3ba511f8c494182663d692b9d89ed6c1e..04454cb7b24a534e84c8873a8babeb9614a8da60 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mount.h>
 #include <linux/list.h>
 #include <linux/cred.h>
+#include <linux/poll.h>
 struct linux_binprm;
 
 /********** Constants definitions. **********/
@@ -32,20 +33,44 @@ struct linux_binprm;
 #define TOMOYO_HASH_BITS  8
 #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
 
-/*
- * This is the max length of a token.
- *
- * A token consists of only ASCII printable characters.
- * Non printable characters in a token is represented in \ooo style
- * octal string. Thus, \ itself is represented as \\.
- */
-#define TOMOYO_MAX_PATHNAME_LEN 4000
+#define TOMOYO_EXEC_TMPSIZE     4096
 
 /* Profile number is an integer between 0 and 255. */
 #define TOMOYO_MAX_PROFILES 256
 
+enum tomoyo_mode_index {
+       TOMOYO_CONFIG_DISABLED,
+       TOMOYO_CONFIG_LEARNING,
+       TOMOYO_CONFIG_PERMISSIVE,
+       TOMOYO_CONFIG_ENFORCING,
+       TOMOYO_CONFIG_USE_DEFAULT = 255
+};
+
+enum tomoyo_policy_id {
+       TOMOYO_ID_GROUP,
+       TOMOYO_ID_PATH_GROUP,
+       TOMOYO_ID_NUMBER_GROUP,
+       TOMOYO_ID_TRANSITION_CONTROL,
+       TOMOYO_ID_AGGREGATOR,
+       TOMOYO_ID_GLOBALLY_READABLE,
+       TOMOYO_ID_PATTERN,
+       TOMOYO_ID_NO_REWRITE,
+       TOMOYO_ID_MANAGER,
+       TOMOYO_ID_NAME,
+       TOMOYO_ID_ACL,
+       TOMOYO_ID_DOMAIN,
+       TOMOYO_MAX_POLICY
+};
+
+enum tomoyo_group_id {
+       TOMOYO_PATH_GROUP,
+       TOMOYO_NUMBER_GROUP,
+       TOMOYO_MAX_GROUP
+};
+
 /* Keywords for ACLs. */
-#define TOMOYO_KEYWORD_ALIAS                     "alias "
+#define TOMOYO_KEYWORD_AGGREGATOR                "aggregator "
+#define TOMOYO_KEYWORD_ALLOW_MOUNT               "allow_mount "
 #define TOMOYO_KEYWORD_ALLOW_READ                "allow_read "
 #define TOMOYO_KEYWORD_DELETE                    "delete "
 #define TOMOYO_KEYWORD_DENY_REWRITE              "deny_rewrite "
@@ -55,36 +80,51 @@ struct linux_binprm;
 #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN      "no_initialize_domain "
 #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN            "no_keep_domain "
 #define TOMOYO_KEYWORD_PATH_GROUP                "path_group "
+#define TOMOYO_KEYWORD_NUMBER_GROUP              "number_group "
 #define TOMOYO_KEYWORD_SELECT                    "select "
 #define TOMOYO_KEYWORD_USE_PROFILE               "use_profile "
 #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ  "ignore_global_allow_read"
+#define TOMOYO_KEYWORD_QUOTA_EXCEEDED            "quota_exceeded"
+#define TOMOYO_KEYWORD_TRANSITION_FAILED         "transition_failed"
 /* A domain definition starts with <kernel>. */
 #define TOMOYO_ROOT_NAME                         "<kernel>"
 #define TOMOYO_ROOT_NAME_LEN                     (sizeof(TOMOYO_ROOT_NAME) - 1)
 
-/* Index numbers for Access Controls. */
-enum tomoyo_mac_index {
-       TOMOYO_MAC_FOR_FILE,  /* domain_policy.conf */
-       TOMOYO_MAX_ACCEPT_ENTRY,
-       TOMOYO_VERBOSE,
-       TOMOYO_MAX_CONTROL_INDEX
+/* Value type definition. */
+#define TOMOYO_VALUE_TYPE_INVALID     0
+#define TOMOYO_VALUE_TYPE_DECIMAL     1
+#define TOMOYO_VALUE_TYPE_OCTAL       2
+#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
+
+enum tomoyo_transition_type {
+       /* Do not change this order, */
+       TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
+       TOMOYO_TRANSITION_CONTROL_INITIALIZE,
+       TOMOYO_TRANSITION_CONTROL_NO_KEEP,
+       TOMOYO_TRANSITION_CONTROL_KEEP,
+       TOMOYO_MAX_TRANSITION_TYPE
 };
 
 /* Index numbers for Access Controls. */
 enum tomoyo_acl_entry_type_index {
        TOMOYO_TYPE_PATH_ACL,
        TOMOYO_TYPE_PATH2_ACL,
+       TOMOYO_TYPE_PATH_NUMBER_ACL,
+       TOMOYO_TYPE_MKDEV_ACL,
+       TOMOYO_TYPE_MOUNT_ACL,
 };
 
 /* Index numbers for File Controls. */
 
 /*
- * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
- * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
- * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
- * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
- * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
- * automatically cleared if TYPE_READ_WRITE_ACL is cleared.
+ * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically
+ * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if
+ * TOMOYO_TYPE_READ_WRITE is set.
+ * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ
+ * or TOMOYO_TYPE_WRITE is cleared.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if
+ * TOMOYO_TYPE_READ_WRITE is cleared.
  */
 
 enum tomoyo_path_acl_index {
@@ -92,27 +132,24 @@ enum tomoyo_path_acl_index {
        TOMOYO_TYPE_EXECUTE,
        TOMOYO_TYPE_READ,
        TOMOYO_TYPE_WRITE,
-       TOMOYO_TYPE_CREATE,
        TOMOYO_TYPE_UNLINK,
-       TOMOYO_TYPE_MKDIR,
        TOMOYO_TYPE_RMDIR,
-       TOMOYO_TYPE_MKFIFO,
-       TOMOYO_TYPE_MKSOCK,
-       TOMOYO_TYPE_MKBLOCK,
-       TOMOYO_TYPE_MKCHAR,
        TOMOYO_TYPE_TRUNCATE,
        TOMOYO_TYPE_SYMLINK,
        TOMOYO_TYPE_REWRITE,
-       TOMOYO_TYPE_IOCTL,
-       TOMOYO_TYPE_CHMOD,
-       TOMOYO_TYPE_CHOWN,
-       TOMOYO_TYPE_CHGRP,
        TOMOYO_TYPE_CHROOT,
-       TOMOYO_TYPE_MOUNT,
        TOMOYO_TYPE_UMOUNT,
        TOMOYO_MAX_PATH_OPERATION
 };
 
+#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE))
+
+enum tomoyo_mkdev_acl_index {
+       TOMOYO_TYPE_MKBLOCK,
+       TOMOYO_TYPE_MKCHAR,
+       TOMOYO_MAX_MKDEV_OPERATION
+};
+
 enum tomoyo_path2_acl_index {
        TOMOYO_TYPE_LINK,
        TOMOYO_TYPE_RENAME,
@@ -120,6 +157,18 @@ enum tomoyo_path2_acl_index {
        TOMOYO_MAX_PATH2_OPERATION
 };
 
+enum tomoyo_path_number_acl_index {
+       TOMOYO_TYPE_CREATE,
+       TOMOYO_TYPE_MKDIR,
+       TOMOYO_TYPE_MKFIFO,
+       TOMOYO_TYPE_MKSOCK,
+       TOMOYO_TYPE_IOCTL,
+       TOMOYO_TYPE_CHMOD,
+       TOMOYO_TYPE_CHOWN,
+       TOMOYO_TYPE_CHGRP,
+       TOMOYO_MAX_PATH_NUMBER_OPERATION
+};
+
 enum tomoyo_securityfs_interface_index {
        TOMOYO_DOMAINPOLICY,
        TOMOYO_EXCEPTIONPOLICY,
@@ -129,20 +178,109 @@ enum tomoyo_securityfs_interface_index {
        TOMOYO_SELFDOMAIN,
        TOMOYO_VERSION,
        TOMOYO_PROFILE,
+       TOMOYO_QUERY,
        TOMOYO_MANAGER
 };
 
+enum tomoyo_mac_index {
+       TOMOYO_MAC_FILE_EXECUTE,
+       TOMOYO_MAC_FILE_OPEN,
+       TOMOYO_MAC_FILE_CREATE,
+       TOMOYO_MAC_FILE_UNLINK,
+       TOMOYO_MAC_FILE_MKDIR,
+       TOMOYO_MAC_FILE_RMDIR,
+       TOMOYO_MAC_FILE_MKFIFO,
+       TOMOYO_MAC_FILE_MKSOCK,
+       TOMOYO_MAC_FILE_TRUNCATE,
+       TOMOYO_MAC_FILE_SYMLINK,
+       TOMOYO_MAC_FILE_REWRITE,
+       TOMOYO_MAC_FILE_MKBLOCK,
+       TOMOYO_MAC_FILE_MKCHAR,
+       TOMOYO_MAC_FILE_LINK,
+       TOMOYO_MAC_FILE_RENAME,
+       TOMOYO_MAC_FILE_CHMOD,
+       TOMOYO_MAC_FILE_CHOWN,
+       TOMOYO_MAC_FILE_CHGRP,
+       TOMOYO_MAC_FILE_IOCTL,
+       TOMOYO_MAC_FILE_CHROOT,
+       TOMOYO_MAC_FILE_MOUNT,
+       TOMOYO_MAC_FILE_UMOUNT,
+       TOMOYO_MAC_FILE_PIVOT_ROOT,
+       TOMOYO_MAX_MAC_INDEX
+};
+
+enum tomoyo_mac_category_index {
+       TOMOYO_MAC_CATEGORY_FILE,
+       TOMOYO_MAX_MAC_CATEGORY_INDEX
+};
+
+#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
+
 /********** Structure definitions. **********/
 
 /*
- * tomoyo_page_buffer is a structure which is used for holding a pathname
- * obtained from "struct dentry" and "struct vfsmount" pair.
- * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
- * (because TOMOYO escapes non ASCII printable characters using \ooo format),
- * we will make the buffer larger.
+ * tomoyo_acl_head is a structure which is used for holding elements not in
+ * domain policy.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_policy_list[] .
+ *  (2) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
  */
-struct tomoyo_page_buffer {
-       char buffer[4096];
+struct tomoyo_acl_head {
+       struct list_head list;
+       bool is_deleted;
+} __packed;
+
+/*
+ * tomoyo_request_info is a structure which is used for holding
+ *
+ * (1) Domain information of current process.
+ * (2) How many retries are made for this request.
+ * (3) Profile number used for this request.
+ * (4) Access control mode of the profile.
+ */
+struct tomoyo_request_info {
+       struct tomoyo_domain_info *domain;
+       /* For holding parameters. */
+       union {
+               struct {
+                       const struct tomoyo_path_info *filename;
+                       /* For using wildcards at tomoyo_find_next_domain(). */
+                       const struct tomoyo_path_info *matched_path;
+                       u8 operation;
+               } path;
+               struct {
+                       const struct tomoyo_path_info *filename1;
+                       const struct tomoyo_path_info *filename2;
+                       u8 operation;
+               } path2;
+               struct {
+                       const struct tomoyo_path_info *filename;
+                       unsigned int mode;
+                       unsigned int major;
+                       unsigned int minor;
+                       u8 operation;
+               } mkdev;
+               struct {
+                       const struct tomoyo_path_info *filename;
+                       unsigned long number;
+                       u8 operation;
+               } path_number;
+               struct {
+                       const struct tomoyo_path_info *type;
+                       const struct tomoyo_path_info *dir;
+                       const struct tomoyo_path_info *dev;
+                       unsigned long flags;
+                       int need_dev;
+               } mount;
+       } param;
+       u8 param_type;
+       bool granted;
+       u8 retry;
+       u8 profile;
+       u8 mode; /* One of tomoyo_mode_index . */
+       u8 type;
 };
 
 /*
@@ -174,45 +312,31 @@ struct tomoyo_path_info {
 };
 
 /*
- * tomoyo_name_entry is a structure which is used for linking
+ * tomoyo_name is a structure which is used for linking
  * "struct tomoyo_path_info" into tomoyo_name_list .
  */
-struct tomoyo_name_entry {
+struct tomoyo_name {
        struct list_head list;
        atomic_t users;
        struct tomoyo_path_info entry;
 };
 
-/*
- * tomoyo_path_info_with_data is a structure which is used for holding a
- * pathname obtained from "struct dentry" and "struct vfsmount" pair.
- *
- * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
- * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
- * buffer for the pathname only.
- *
- * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
- * both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
- * so that we don't need to return two pointers to the caller. If the caller
- * puts "struct tomoyo_path_info" on stack memory, we will be able to remove
- * "struct tomoyo_path_info_with_data".
- */
-struct tomoyo_path_info_with_data {
-       /* Keep "head" first, for this pointer is passed to kfree(). */
-       struct tomoyo_path_info head;
-       char barrier1[16]; /* Safeguard for overrun. */
-       char body[TOMOYO_MAX_PATHNAME_LEN];
-       char barrier2[16]; /* Safeguard for overrun. */
-};
-
 struct tomoyo_name_union {
        const struct tomoyo_path_info *filename;
-       struct tomoyo_path_group *group;
+       struct tomoyo_group *group;
        u8 is_group;
 };
 
-/* Structure for "path_group" directive. */
-struct tomoyo_path_group {
+struct tomoyo_number_union {
+       unsigned long values[2];
+       struct tomoyo_group *group;
+       u8 min_type;
+       u8 max_type;
+       u8 is_group;
+};
+
+/* Structure for "path_group"/"number_group" directive. */
+struct tomoyo_group {
        struct list_head list;
        const struct tomoyo_path_info *group_name;
        struct list_head member_list;
@@ -220,28 +344,35 @@ struct tomoyo_path_group {
 };
 
 /* Structure for "path_group" directive. */
-struct tomoyo_path_group_member {
-       struct list_head list;
-       bool is_deleted;
+struct tomoyo_path_group {
+       struct tomoyo_acl_head head;
        const struct tomoyo_path_info *member_name;
 };
 
+/* Structure for "number_group" directive. */
+struct tomoyo_number_group {
+       struct tomoyo_acl_head head;
+       struct tomoyo_number_union number;
+};
+
 /*
  * tomoyo_acl_info is a structure which is used for holding
  *
  *  (1) "list" which is linked to the ->acl_info_list of
  *      "struct tomoyo_domain_info"
- *  (2) "type" which tells type of the entry (either
- *      "struct tomoyo_path_acl" or "struct tomoyo_path2_acl").
+ *  (2) "is_deleted" is a bool which is true if this domain is marked as
+ *      "deleted", false otherwise.
+ *  (3) "type" which tells type of the entry.
  *
  * Packing "struct tomoyo_acl_info" allows
- * "struct tomoyo_path_acl" to embed "u8" + "u16" and
- * "struct tomoyo_path2_acl" to embed "u8"
- * without enlarging their structure size.
+ * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl"
+ * "struct tomoyo_path_number_acl" "struct tomoyo_mkdev_acl" to embed
+ * "u8" without enlarging their structure size.
  */
 struct tomoyo_acl_info {
        struct list_head list;
-       u8 type;
+       bool is_deleted;
+       u8 type; /* = one of values in "enum tomoyo_acl_entry_type_index". */
 } __packed;
 
 /*
@@ -299,19 +430,61 @@ struct tomoyo_domain_info {
  *  (3) "name" is the pathname.
  *
  * Directives held by this structure are "allow_read/write", "allow_execute",
- * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
- * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock",
- * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite",
- * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount"
- * and "allow_unmount".
+ * "allow_read", "allow_write", "allow_unlink", "allow_rmdir",
+ * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and
+ * "allow_unmount".
  */
 struct tomoyo_path_acl {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
-       u8 perm_high;
        u16 perm;
        struct tomoyo_name_union name;
 };
 
+/*
+ * tomoyo_path_number_acl is a structure which is used for holding an
+ * entry with one pathname and one number operation.
+ * It has following fields.
+ *
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "perm" which is a bitmask of permitted operations.
+ *  (3) "name" is the pathname.
+ *  (4) "number" is the numeric value.
+ *
+ * Directives held by this structure are "allow_create", "allow_mkdir",
+ * "allow_ioctl", "allow_mkfifo", "allow_mksock", "allow_chmod", "allow_chown"
+ * and "allow_chgrp".
+ *
+ */
+struct tomoyo_path_number_acl {
+       struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */
+       u8 perm;
+       struct tomoyo_name_union name;
+       struct tomoyo_number_union number;
+};
+
+/*
+ * tomoyo_mkdev_acl is a structure which is used for holding an
+ * entry with one pathname and three numbers operation.
+ * It has following fields.
+ *
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "perm" which is a bitmask of permitted operations.
+ *  (3) "mode" is the create mode.
+ *  (4) "major" is the major number of device node.
+ *  (5) "minor" is the minor number of device node.
+ *
+ * Directives held by this structure are "allow_mkchar", "allow_mkblock".
+ *
+ */
+struct tomoyo_mkdev_acl {
+       struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */
+       u8 perm;
+       struct tomoyo_name_union name;
+       struct tomoyo_number_union mode;
+       struct tomoyo_number_union major;
+       struct tomoyo_number_union minor;
+};
+
 /*
  * tomoyo_path2_acl is a structure which is used for holding an
  * entry with two pathnames operation (i.e. link(), rename() and pivot_root()).
@@ -333,53 +506,61 @@ struct tomoyo_path2_acl {
 };
 
 /*
- * tomoyo_io_buffer is a structure which is used for reading and modifying
- * configuration via /sys/kernel/security/tomoyo/ interface.
- * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as
- * cursors.
+ * tomoyo_mount_acl is a structure which is used for holding an
+ * entry for mount operation.
+ * It has following fields.
  *
- * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of
- * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info"
- * entry has a list of "struct tomoyo_acl_info", we need two cursors when
- * reading (one is for traversing tomoyo_domain_list and the other is for
- * traversing "struct tomoyo_acl_info"->acl_info_list ).
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "dev_name" is the device name.
+ *  (3) "dir_name" is the mount point.
+ *  (4) "fs_type" is the filesystem type.
+ *  (5) "flags" is the mount flags.
  *
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the
- * domain with the domainname specified by the rest of that line (NULL is set
- * if seek failed).
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that
- * line (->write_var1 is set to NULL if a domain was deleted).
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * neither "select " nor "delete ", an entry or a domain specified by that line
- * is appended.
+ * Directive held by this structure is "allow_mount".
+ */
+struct tomoyo_mount_acl {
+       struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
+       struct tomoyo_name_union dev_name;
+       struct tomoyo_name_union dir_name;
+       struct tomoyo_name_union fs_type;
+       struct tomoyo_number_union flags;
+};
+
+#define TOMOYO_MAX_IO_READ_QUEUE 32
+
+/*
+ * Structure for reading/writing policy via /sys/kernel/security/tomoyo
+ * interfaces.
  */
 struct tomoyo_io_buffer {
-       int (*read) (struct tomoyo_io_buffer *);
+       void (*read) (struct tomoyo_io_buffer *);
        int (*write) (struct tomoyo_io_buffer *);
+       int (*poll) (struct file *file, poll_table *wait);
        /* Exclusive lock for this structure.   */
        struct mutex io_sem;
        /* Index returned by tomoyo_read_lock(). */
        int reader_idx;
-       /* The position currently reading from. */
-       struct list_head *read_var1;
-       /* Extra variables for reading.         */
-       struct list_head *read_var2;
+       char __user *read_user_buf;
+       int read_user_buf_avail;
+       struct {
+               struct list_head *domain;
+               struct list_head *group;
+               struct list_head *acl;
+               int avail;
+               int step;
+               int query_index;
+               u16 index;
+               u8 bit;
+               u8 w_pos;
+               bool eof;
+               bool print_this_domain_only;
+               bool print_execute_only;
+               const char *w[TOMOYO_MAX_IO_READ_QUEUE];
+       } r;
        /* The position currently writing to.   */
        struct tomoyo_domain_info *write_var1;
-       /* The step for reading.                */
-       int read_step;
        /* Buffer for reading.                  */
        char *read_buf;
-       /* EOF flag for reading.                */
-       bool read_eof;
-       /* Read domain ACL of specified PID?    */
-       bool read_single_domain;
-       /* Extra variable for reading.          */
-       u8 read_bit;
-       /* Bytes available for reading.         */
-       int read_avail;
        /* Size of read buffer.                 */
        int readbuf_size;
        /* Buffer for writing.                  */
@@ -388,215 +569,203 @@ struct tomoyo_io_buffer {
        int write_avail;
        /* Size of write buffer.                */
        int writebuf_size;
+       /* Type of this interface.              */
+       u8 type;
 };
 
 /*
- * tomoyo_globally_readable_file_entry is a structure which is used for holding
+ * tomoyo_readable_file is a structure which is used for holding
  * "allow_read" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_globally_readable_list .
+ *  (1) "head" is "struct tomoyo_acl_head".
  *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
  */
-struct tomoyo_globally_readable_file_entry {
-       struct list_head list;
+struct tomoyo_readable_file {
+       struct tomoyo_acl_head head;
        const struct tomoyo_path_info *filename;
-       bool is_deleted;
 };
 
 /*
- * tomoyo_pattern_entry is a structure which is used for holding
- * "tomoyo_pattern_list" entries.
+ * tomoyo_no_pattern is a structure which is used for holding
+ * "file_pattern" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_pattern_list .
+ *  (1) "head" is "struct tomoyo_acl_head".
  *  (2) "pattern" is a pathname pattern which is used for converting pathnames
  *      to pathname patterns during learning mode.
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
  */
-struct tomoyo_pattern_entry {
-       struct list_head list;
+struct tomoyo_no_pattern {
+       struct tomoyo_acl_head head;
        const struct tomoyo_path_info *pattern;
-       bool is_deleted;
 };
 
 /*
- * tomoyo_no_rewrite_entry is a structure which is used for holding
+ * tomoyo_no_rewrite is a structure which is used for holding
  * "deny_rewrite" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_no_rewrite_list .
+ *  (1) "head" is "struct tomoyo_acl_head".
  *  (2) "pattern" is a pathname which is by default not permitted to modify
  *      already existing content.
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
  */
-struct tomoyo_no_rewrite_entry {
-       struct list_head list;
+struct tomoyo_no_rewrite {
+       struct tomoyo_acl_head head;
        const struct tomoyo_path_info *pattern;
-       bool is_deleted;
 };
 
 /*
- * tomoyo_domain_initializer_entry is a structure which is used for holding
- * "initialize_domain" and "no_initialize_domain" entries.
+ * tomoyo_transition_control is a structure which is used for holding
+ * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain"
+ * entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_domain_initializer_list .
- *  (2) "domainname" which is "a domainname" or "the last component of a
- *      domainname". This field is NULL if "from" clause is not specified.
- *  (3) "program" which is a program's pathname.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
- *      otherwise.
- *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
+ *  (1) "head" is "struct tomoyo_acl_head".
+ *  (2) "type" is type of this entry.
+ *  (3) "is_last_name" is a bool which is true if "domainname" is "the last
  *      component of a domainname", false otherwise.
- */
-struct tomoyo_domain_initializer_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *domainname;    /* This may be NULL */
-       const struct tomoyo_path_info *program;
-       bool is_deleted;
-       bool is_not;       /* True if this entry is "no_initialize_domain".  */
-       /* True if the domainname is tomoyo_get_last_name(). */
-       bool is_last_name;
-};
-
-/*
- * tomoyo_domain_keeper_entry is a structure which is used for holding
- * "keep_domain" and "no_keep_domain" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_domain_keeper_list .
- *  (2) "domainname" which is "a domainname" or "the last component of a
+ *  (4) "domainname" which is "a domainname" or "the last component of a
  *      domainname".
- *  (3) "program" which is a program's pathname.
- *      This field is NULL if "from" clause is not specified.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
- *      otherwise.
- *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
- *      component of a domainname", false otherwise.
+ *  (5) "program" which is a program's pathname.
  */
-struct tomoyo_domain_keeper_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *domainname;
-       const struct tomoyo_path_info *program;       /* This may be NULL */
-       bool is_deleted;
-       bool is_not;       /* True if this entry is "no_keep_domain".        */
+struct tomoyo_transition_control {
+       struct tomoyo_acl_head head;
+       u8 type; /* One of values in "enum tomoyo_transition_type".  */
        /* True if the domainname is tomoyo_get_last_name(). */
        bool is_last_name;
+       const struct tomoyo_path_info *domainname; /* Maybe NULL */
+       const struct tomoyo_path_info *program;    /* Maybe NULL */
 };
 
 /*
- * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
+ * tomoyo_aggregator is a structure which is used for holding
+ * "aggregator" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_alias_list .
- *  (2) "original_name" which is a dereferenced pathname.
- *  (3) "aliased_name" which is a symlink's pathname.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
+ *  (1) "head" is "struct tomoyo_acl_head".
+ *  (2) "original_name" which is originally requested name.
+ *  (3) "aggregated_name" which is name to rewrite.
  */
-struct tomoyo_alias_entry {
-       struct list_head list;
+struct tomoyo_aggregator {
+       struct tomoyo_acl_head head;
        const struct tomoyo_path_info *original_name;
-       const struct tomoyo_path_info *aliased_name;
-       bool is_deleted;
+       const struct tomoyo_path_info *aggregated_name;
 };
 
 /*
- * tomoyo_policy_manager_entry is a structure which is used for holding list of
+ * tomoyo_manager is a structure which is used for holding list of
  * domainnames or programs which are permitted to modify configuration via
  * /sys/kernel/security/tomoyo/ interface.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_policy_manager_list .
- *  (2) "manager" is a domainname or a program's pathname.
- *  (3) "is_domain" is a bool which is true if "manager" is a domainname, false
- *      otherwise.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
+ *  (1) "head" is "struct tomoyo_acl_head".
+ *  (2) "is_domain" is a bool which is true if "manager" is a domainname, false
  *      otherwise.
+ *  (3) "manager" is a domainname or a program's pathname.
  */
-struct tomoyo_policy_manager_entry {
-       struct list_head list;
+struct tomoyo_manager {
+       struct tomoyo_acl_head head;
+       bool is_domain;  /* True if manager is a domainname. */
        /* A path to program or a domainname. */
        const struct tomoyo_path_info *manager;
-       bool is_domain;  /* True if manager is a domainname. */
-       bool is_deleted; /* True if this entry is deleted. */
+};
+
+struct tomoyo_preference {
+       unsigned int learning_max_entry;
+       bool enforcing_verbose;
+       bool learning_verbose;
+       bool permissive_verbose;
+};
+
+struct tomoyo_profile {
+       const struct tomoyo_path_info *comment;
+       struct tomoyo_preference *learning;
+       struct tomoyo_preference *permissive;
+       struct tomoyo_preference *enforcing;
+       struct tomoyo_preference preference;
+       u8 default_config;
+       u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
 };
 
 /********** Function prototypes. **********/
 
-/* Check whether the given name matches the given name_union. */
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
-                              const struct tomoyo_name_union *ptr);
+extern asmlinkage long sys_getpid(void);
+extern asmlinkage long sys_getppid(void);
+
+/* Check whether the given string starts with the given keyword. */
+bool tomoyo_str_starts(char **src, const char *find);
+/* Get tomoyo_realpath() of current process. */
+const char *tomoyo_get_exe(void);
+/* Format string. */
+void tomoyo_normalize_line(unsigned char *buffer);
+/* Print warning or error message on console. */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+     __attribute__ ((format(printf, 2, 3)));
+/* Check all profiles currently assigned to domains are defined. */
+void tomoyo_check_profile(void);
+/* Open operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_open_control(const u8 type, struct file *file);
+/* Close /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_close_control(struct file *file);
+/* Poll operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_poll_control(struct file *file, poll_table *wait);
+/* Read operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_read_control(struct file *file, char __user *buffer,
+                       const int buffer_len);
+/* Write operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+                        const int buffer_len);
 /* Check whether the domain has too many ACL entries to hold. */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
-/* Transactional sprintf() for policy dump. */
-bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
+/* Print out of memory warning message. */
+void tomoyo_warn_oom(const char *function);
+/* Check whether the given name matches the given name_union. */
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+                         const struct tomoyo_name_union *ptr);
+/* Check whether the given number matches the given number_union. */
+bool tomoyo_compare_number_union(const unsigned long value,
+                                const struct tomoyo_number_union *ptr);
+int tomoyo_get_mode(const u8 profile, const u8 index);
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
        __attribute__ ((format(printf, 2, 3)));
 /* Check whether the domainname is correct. */
-bool tomoyo_is_correct_domain(const unsigned char *domainname);
+bool tomoyo_correct_domain(const unsigned char *domainname);
 /* Check whether the token is correct. */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
-                           const s8 pattern_type, const s8 end_type);
+bool tomoyo_correct_path(const char *filename);
+bool tomoyo_correct_word(const char *string);
 /* Check whether the token can be a domainname. */
-bool tomoyo_is_domain_def(const unsigned char *buffer);
+bool tomoyo_domain_def(const unsigned char *buffer);
 bool tomoyo_parse_name_union(const char *filename,
                             struct tomoyo_name_union *ptr);
 /* Check whether the given filename matches the given path_group. */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-                              const struct tomoyo_path_group *group,
-                              const bool may_use_pattern);
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+                         const struct tomoyo_group *group);
+/* Check whether the given value matches the given number_group. */
+bool tomoyo_number_matches_group(const unsigned long min,
+                                const unsigned long max,
+                                const struct tomoyo_group *group);
 /* Check whether the given filename matches the given pattern. */
 bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
                                 const struct tomoyo_path_info *pattern);
-/* Read "alias" entry in exception policy. */
-bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head);
-/*
- * Read "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head);
-/* Read "keep_domain" and "no_keep_domain" entry in exception policy. */
-bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head);
-/* Read "file_pattern" entry in exception policy. */
-bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head);
-/* Read "path_group" entry in exception policy. */
-bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head);
-/* Read "allow_read" entry in exception policy. */
-bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
-/* Read "deny_rewrite" entry in exception policy. */
-bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head);
+
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
 /* Tokenize a line. */
 bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
 /* Write domain policy violation warning message to console? */
 bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
-/* Convert double path operation to operation name. */
-const char *tomoyo_path22keyword(const u8 operation);
-/* Get the last component of the given domainname. */
-const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
-/* Get warning message. */
-const char *tomoyo_get_msg(const bool is_enforce);
-/* Convert single path operation to operation name. */
-const char *tomoyo_path2keyword(const u8 operation);
-/* Create "alias" entry in exception policy. */
-int tomoyo_write_alias_policy(char *data, const bool is_delete);
-/*
- * Create "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
-                                          const bool is_delete);
-/* Create "keep_domain" and "no_keep_domain" entry in exception policy. */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
-                                     const bool is_delete);
+/* Fill "struct tomoyo_request_info". */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+                            struct tomoyo_domain_info *domain,
+                            const u8 index);
+/* Check permission for mount operation. */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+                           unsigned long flags, void *data_page);
+/* Create "aggregator" entry in exception policy. */
+int tomoyo_write_aggregator(char *data, const bool is_delete);
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+                                   const u8 type);
 /*
  * Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
  * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
@@ -604,25 +773,31 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
  * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and
  * "allow_link" entry in domain policy.
  */
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
-                            const bool is_delete);
+int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
+                     const bool is_delete);
 /* Create "allow_read" entry in exception policy. */
-int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
+int tomoyo_write_globally_readable(char *data, const bool is_delete);
+/* Create "allow_mount" entry in domain policy. */
+int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
+                      const bool is_delete);
 /* Create "deny_rewrite" entry in exception policy. */
-int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
+int tomoyo_write_no_rewrite(char *data, const bool is_delete);
 /* Create "file_pattern" entry in exception policy. */
-int tomoyo_write_pattern_policy(char *data, const bool is_delete);
-/* Create "path_group" entry in exception policy. */
-int tomoyo_write_path_group_policy(char *data, const bool is_delete);
+int tomoyo_write_pattern(char *data, const bool is_delete);
+/* Create "path_group"/"number_group" entry in exception policy. */
+int tomoyo_write_group(char *data, const bool is_delete, const u8 type);
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+     __attribute__ ((format(printf, 2, 3)));
 /* Find a domain by the given name. */
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
 /* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-                                                           domainname,
-                                                           const u8 profile);
-
-/* Allocate memory for "struct tomoyo_path_group". */
-struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+                                               const u8 profile);
+struct tomoyo_profile *tomoyo_profile(const u8 profile);
+/*
+ * Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ */
+struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type);
 
 /* Check mode for specified functionality. */
 unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
@@ -632,25 +807,23 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
 /* Run policy loader when /sbin/init starts. */
 void tomoyo_load_policy(const char *filename);
 
-/* Convert binary string to ascii string. */
-int tomoyo_encode(char *buffer, int buflen, const char *str);
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
 
-/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
-                              int newname_len);
+/* Convert binary string to ascii string. */
+char *tomoyo_encode(const char *str);
 
 /*
- * Returns realpath(3) of the given pathname but ignores chroot'ed root.
- * These functions use kzalloc(), so the caller must call kfree()
- * if these functions didn't return NULL.
+ * Returns realpath(3) of the given pathname except that
+ * ignores chroot'ed root and does not follow the final symlink.
  */
-char *tomoyo_realpath(const char *pathname);
+char *tomoyo_realpath_nofollow(const char *pathname);
 /*
- * Same with tomoyo_realpath() except that it doesn't follow the final symlink.
+ * Returns realpath(3) of the given pathname except that
+ * ignores chroot'ed root and the pathname is already solved.
  */
-char *tomoyo_realpath_nofollow(const char *pathname);
-/* Same with tomoyo_realpath() except that the pathname is already solved. */
 char *tomoyo_realpath_from_path(struct path *path);
+/* Get patterned pathname. */
+const char *tomoyo_pattern(const struct tomoyo_path_info *filename);
 
 /* Check memory quota. */
 bool tomoyo_memory_ok(void *ptr);
@@ -663,23 +836,29 @@ void *tomoyo_commit_ok(void *data, const unsigned int size);
 const struct tomoyo_path_info *tomoyo_get_name(const char *name);
 
 /* Check for memory usage. */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
 
 /* Set memory quota. */
 int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
 
-/* Initialize realpath related code. */
-void __init tomoyo_realpath_init(void);
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+/* Initialize mm related code. */
+void __init tomoyo_mm_init(void);
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
                           const struct tomoyo_path_info *filename);
 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
                                 struct path *path, const int flag);
+int tomoyo_path_number_perm(const u8 operation, struct path *path,
+                           unsigned long number);
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+                     const unsigned int mode, unsigned int dev);
 int tomoyo_path_perm(const u8 operation, struct path *path);
 int tomoyo_path2_perm(const u8 operation, struct path *path1,
                      struct path *path2);
-int tomoyo_check_rewrite_permission(struct file *filp);
 int tomoyo_find_next_domain(struct linux_binprm *bprm);
 
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+                       const unsigned long value, const u8 type);
+
 /* Drop refcount on tomoyo_name_union. */
 void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
 
@@ -688,6 +867,25 @@ void tomoyo_run_gc(void);
 
 void tomoyo_memory_free(void *ptr);
 
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+                        bool is_delete, struct tomoyo_domain_info *domain,
+                        bool (*check_duplicate) (const struct tomoyo_acl_info
+                                                 *,
+                                                 const struct tomoyo_acl_info
+                                                 *),
+                        bool (*merge_duplicate) (struct tomoyo_acl_info *,
+                                                 struct tomoyo_acl_info *,
+                                                 const bool));
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+                        bool is_delete, struct list_head *list,
+                        bool (*check_duplicate) (const struct tomoyo_acl_head
+                                                 *,
+                                                 const struct tomoyo_acl_head
+                                                 *));
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+                     bool (*check_entry) (struct tomoyo_request_info *,
+                                          const struct tomoyo_acl_info *));
+
 /********** External variable definitions. **********/
 
 /* Lock for GC. */
@@ -696,14 +894,8 @@ extern struct srcu_struct tomoyo_ss;
 /* The list for "struct tomoyo_domain_info". */
 extern struct list_head tomoyo_domain_list;
 
-extern struct list_head tomoyo_path_group_list;
-extern struct list_head tomoyo_domain_initializer_list;
-extern struct list_head tomoyo_domain_keeper_list;
-extern struct list_head tomoyo_alias_list;
-extern struct list_head tomoyo_globally_readable_list;
-extern struct list_head tomoyo_pattern_list;
-extern struct list_head tomoyo_no_rewrite_list;
-extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
+extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
 extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
 
 /* Lock for protecting policy. */
@@ -715,6 +907,14 @@ extern bool tomoyo_policy_loaded;
 /* The kernel's domain. */
 extern struct tomoyo_domain_info tomoyo_kernel_domain;
 
+extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
+extern const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION];
+extern const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION];
+
+extern unsigned int tomoyo_quota_for_query;
+extern unsigned int tomoyo_query_memory_size;
+
 /********** Inlined functions. **********/
 
 static inline int tomoyo_read_lock(void)
@@ -735,25 +935,25 @@ static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
 }
 
 /**
- * tomoyo_is_valid - Check whether the character is a valid char.
+ * tomoyo_valid - Check whether the character is a valid char.
  *
  * @c: The character to check.
  *
  * Returns true if @c is a valid character, false otherwise.
  */
-static inline bool tomoyo_is_valid(const unsigned char c)
+static inline bool tomoyo_valid(const unsigned char c)
 {
        return c > ' ' && c < 127;
 }
 
 /**
- * tomoyo_is_invalid - Check whether the character is an invalid char.
+ * tomoyo_invalid - Check whether the character is an invalid char.
  *
  * @c: The character to check.
  *
  * Returns true if @c is an invalid character, false otherwise.
  */
-static inline bool tomoyo_is_invalid(const unsigned char c)
+static inline bool tomoyo_invalid(const unsigned char c)
 {
        return c && (c <= ' ' || c >= 127);
 }
@@ -761,13 +961,13 @@ static inline bool tomoyo_is_invalid(const unsigned char c)
 static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
 {
        if (name) {
-               struct tomoyo_name_entry *ptr =
-                       container_of(name, struct tomoyo_name_entry, entry);
+               struct tomoyo_name *ptr =
+                       container_of(name, typeof(*ptr), entry);
                atomic_dec(&ptr->users);
        }
 }
 
-static inline void tomoyo_put_path_group(struct tomoyo_path_group *group)
+static inline void tomoyo_put_group(struct tomoyo_group *group)
 {
        if (group)
                atomic_dec(&group->users);
@@ -784,75 +984,35 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
        return task_cred_xxx(task, security);
 }
 
-static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1,
+static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *p1,
                                           const struct tomoyo_acl_info *p2)
 {
        return p1->type == p2->type;
 }
 
-static inline bool tomoyo_is_same_name_union
+static inline bool tomoyo_same_name_union
 (const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2)
 {
        return p1->filename == p2->filename && p1->group == p2->group &&
                p1->is_group == p2->is_group;
 }
 
-static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
-                                          const struct tomoyo_path_acl *p2)
-{
-       return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
-               tomoyo_is_same_name_union(&p1->name, &p2->name);
-}
-
-static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
-                                           const struct tomoyo_path2_acl *p2)
+static inline bool tomoyo_same_number_union
+(const struct tomoyo_number_union *p1, const struct tomoyo_number_union *p2)
 {
-       return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
-               tomoyo_is_same_name_union(&p1->name1, &p2->name1) &&
-               tomoyo_is_same_name_union(&p1->name2, &p2->name2);
-}
-
-static inline bool tomoyo_is_same_domain_initializer_entry
-(const struct tomoyo_domain_initializer_entry *p1,
- const struct tomoyo_domain_initializer_entry *p2)
-{
-       return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
-               && p1->domainname == p2->domainname
-               && p1->program == p2->program;
-}
-
-static inline bool tomoyo_is_same_domain_keeper_entry
-(const struct tomoyo_domain_keeper_entry *p1,
- const struct tomoyo_domain_keeper_entry *p2)
-{
-       return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
-               && p1->domainname == p2->domainname
-               && p1->program == p2->program;
-}
-
-static inline bool tomoyo_is_same_alias_entry
-(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
-{
-       return p1->original_name == p2->original_name &&
-               p1->aliased_name == p2->aliased_name;
+       return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1]
+               && p1->group == p2->group && p1->min_type == p2->min_type &&
+               p1->max_type == p2->max_type && p1->is_group == p2->is_group;
 }
 
 /**
  * list_for_each_cookie - iterate over a list with cookie.
  * @pos:        the &struct list_head to use as a loop cursor.
- * @cookie:     the &struct list_head to use as a cookie.
  * @head:       the head for your list.
- *
- * Same with list_for_each_rcu() except that this primitive uses @cookie
- * so that we can continue iteration.
- * @cookie must be NULL when iteration starts, and @cookie will become
- * NULL when iteration finishes.
  */
-#define list_for_each_cookie(pos, cookie, head)                                \
-       for (({ if (!cookie)                                            \
-                                    cookie = head; }),                 \
-                    pos = rcu_dereference((cookie)->next);             \
-            prefetch(pos->next), pos != (head) || ((cookie) = NULL);   \
-            (cookie) = pos, pos = rcu_dereference(pos->next))
+#define list_for_each_cookie(pos, head)                                        \
+       if (!pos)                                                       \
+               pos =  srcu_dereference((head)->next, &tomoyo_ss);      \
+       for ( ; pos != (head); pos = srcu_dereference(pos->next, &tomoyo_ss))
 
 #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
index cd8ba444676344f71543a1cddd42ff3069e0ccf0..35388408e475470b6c2467db248a05b1b01c2ca7 100644 (file)
@@ -1,12 +1,9 @@
 /*
  * security/tomoyo/domain.c
  *
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
+ * Domain transition functions for TOMOYO.
  *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include "common.h"
 /* The initial domain. */
 struct tomoyo_domain_info tomoyo_kernel_domain;
 
-/*
- * tomoyo_domain_list is used for holding list of domains.
- * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
- * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
- *
- * An entry is added by
- *
- * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
- *                                  /sys/kernel/security/tomoyo/domain_policy
- *
- * and is deleted by
- *
- * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
- *                                  /sys/kernel/security/tomoyo/domain_policy
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/domain_policy
- *
- * A domain is added by
- *
- * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
- *
- * and is deleted by
- *
- * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
- *
- * and all domains are retrieved by
- *
- * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
- *
- * Normally, a domainname is monotonically getting longer because a domainname
- * which the process will belong to if an execve() operation succeeds is
- * defined as a concatenation of "current domainname" + "pathname passed to
- * execve()".
- * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
- * exceptions.
- */
-LIST_HEAD(tomoyo_domain_list);
-
 /**
- * tomoyo_get_last_name - Get last component of a domainname.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns the last component of the domainname.
- */
-const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
-{
-       const char *cp0 = domain->domainname->name;
-       const char *cp1 = strrchr(cp0, ' ');
-
-       if (cp1)
-               return cp1 + 1;
-       return cp0;
-}
-
-/*
- * tomoyo_domain_initializer_list is used for holding list of programs which
- * triggers reinitialization of domainname. Normally, a domainname is
- * monotonically getting longer. But sometimes, we restart daemon programs.
- * It would be convenient for us that "a daemon started upon system boot" and
- * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
- * provides a way to shorten domainnames.
+ * tomoyo_update_policy - Update an entry for exception policy.
  *
- * An entry is added by
- *
- * # echo 'initialize_domain /usr/sbin/httpd' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete initialize_domain /usr/sbin/httpd' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, /usr/sbin/httpd will belong to
- * "<kernel> /usr/sbin/httpd" domain.
- *
- * You may specify a domainname using "from" keyword.
- * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
- * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
- * domain to belong to "<kernel> /usr/sbin/httpd" domain.
- *
- * You may add "no_" prefix to "initialize_domain".
- * "initialize_domain /usr/sbin/httpd" and
- * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
- * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
- * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
- */
-LIST_HEAD(tomoyo_domain_initializer_list);
-
-/**
- * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
- *
- * @domainname: The name of domain. May be NULL.
- * @program:    The name of program.
- * @is_not:     True if it is "no_initialize_domain" entry.
- * @is_delete:  True if it is a delete request.
+ * @new_entry:       Pointer to "struct tomoyo_acl_info".
+ * @size:            Size of @new_entry in bytes.
+ * @is_delete:       True if it is a delete request.
+ * @list:            Pointer to "struct list_head".
+ * @check_duplicate: Callback function to find duplicated entry.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_domain_initializer_entry(const char *domainname,
-                                                 const char *program,
-                                                 const bool is_not,
-                                                 const bool is_delete)
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+                        bool is_delete, struct list_head *list,
+                        bool (*check_duplicate) (const struct tomoyo_acl_head
+                                                 *,
+                                                 const struct tomoyo_acl_head
+                                                 *))
 {
-       struct tomoyo_domain_initializer_entry *ptr;
-       struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
        int error = is_delete ? -ENOENT : -ENOMEM;
+       struct tomoyo_acl_head *entry;
 
-       if (!tomoyo_is_correct_path(program, 1, -1, -1))
-               return -EINVAL; /* No patterns allowed. */
-       if (domainname) {
-               if (!tomoyo_is_domain_def(domainname) &&
-                   tomoyo_is_correct_path(domainname, 1, -1, -1))
-                       e.is_last_name = true;
-               else if (!tomoyo_is_correct_domain(domainname))
-                       return -EINVAL;
-               e.domainname = tomoyo_get_name(domainname);
-               if (!e.domainname)
-                       goto out;
-       }
-       e.program = tomoyo_get_name(program);
-       if (!e.program)
-               goto out;
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
-               if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
+               return -ENOMEM;
+       list_for_each_entry_rcu(entry, list, list) {
+               if (!check_duplicate(entry, new_entry))
                        continue;
-               ptr->is_deleted = is_delete;
+               entry->is_deleted = is_delete;
                error = 0;
                break;
        }
-       if (!is_delete && error) {
-               struct tomoyo_domain_initializer_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
+       if (error && !is_delete) {
+               entry = tomoyo_commit_ok(new_entry, size);
                if (entry) {
-                       list_add_tail_rcu(&entry->list,
-                                         &tomoyo_domain_initializer_list);
+                       list_add_tail_rcu(&entry->list, list);
                        error = 0;
                }
        }
        mutex_unlock(&tomoyo_policy_lock);
- out:
-       tomoyo_put_name(e.domainname);
-       tomoyo_put_name(e.program);
        return error;
 }
 
 /**
- * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
+ * tomoyo_update_domain - Update an entry for domain policy.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
+ * @new_entry:       Pointer to "struct tomoyo_acl_info".
+ * @size:            Size of @new_entry in bytes.
+ * @is_delete:       True if it is a delete request.
+ * @domain:          Pointer to "struct tomoyo_domain_info".
+ * @check_duplicate: Callback function to find duplicated entry.
+ * @merge_duplicate: Callback function to merge duplicated entry.
  *
- * Returns true on success, false otherwise.
+ * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+                        bool is_delete, struct tomoyo_domain_info *domain,
+                        bool (*check_duplicate) (const struct tomoyo_acl_info
+                                                 *,
+                                                 const struct tomoyo_acl_info
+                                                 *),
+                        bool (*merge_duplicate) (struct tomoyo_acl_info *,
+                                                 struct tomoyo_acl_info *,
+                                                 const bool))
 {
-       struct list_head *pos;
-       bool done = true;
+       int error = is_delete ? -ENOENT : -ENOMEM;
+       struct tomoyo_acl_info *entry;
 
-       list_for_each_cookie(pos, head->read_var2,
-                            &tomoyo_domain_initializer_list) {
-               const char *no;
-               const char *from = "";
-               const char *domain = "";
-               struct tomoyo_domain_initializer_entry *ptr;
-               ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
-                                 list);
-               if (ptr->is_deleted)
+       if (mutex_lock_interruptible(&tomoyo_policy_lock))
+               return error;
+       list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
+               if (!check_duplicate(entry, new_entry))
                        continue;
-               no = ptr->is_not ? "no_" : "";
-               if (ptr->domainname) {
-                       from = " from ";
-                       domain = ptr->domainname->name;
+               if (merge_duplicate)
+                       entry->is_deleted = merge_duplicate(entry, new_entry,
+                                                           is_delete);
+               else
+                       entry->is_deleted = is_delete;
+               error = 0;
+               break;
+       }
+       if (error && !is_delete) {
+               entry = tomoyo_commit_ok(new_entry, size);
+               if (entry) {
+                       list_add_tail_rcu(&entry->list, &domain->acl_info_list);
+                       error = 0;
                }
-               done = tomoyo_io_printf(head,
-                                       "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
-                                       "%s%s%s\n", no, ptr->program->name,
-                                       from, domain);
-               if (!done)
-                       break;
        }
-       return done;
+       mutex_unlock(&tomoyo_policy_lock);
+       return error;
 }
 
-/**
- * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
- *
- * @data:      String to parse.
- * @is_not:    True if it is "no_initialize_domain" entry.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
-                                          const bool is_delete)
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+                     bool (*check_entry) (struct tomoyo_request_info *,
+                                          const struct tomoyo_acl_info *))
 {
-       char *cp = strstr(data, " from ");
+       const struct tomoyo_domain_info *domain = r->domain;
+       struct tomoyo_acl_info *ptr;
 
-       if (cp) {
-               *cp = '\0';
-               return tomoyo_update_domain_initializer_entry(cp + 6, data,
-                                                             is_not,
-                                                             is_delete);
+       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               if (ptr->is_deleted || ptr->type != r->param_type)
+                       continue;
+               if (check_entry(r, ptr)) {
+                       r->granted = true;
+                       return;
+               }
        }
-       return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
-                                                     is_delete);
+       r->granted = false;
 }
 
+/* The list for "struct tomoyo_domain_info". */
+LIST_HEAD(tomoyo_domain_list);
+
+struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
+struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
+
 /**
- * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
- *
- * @domainname: The name of domain.
- * @program:    The name of program.
- * @last_name:  The last component of @domainname.
+ * tomoyo_last_word - Get last component of a domainname.
  *
- * Returns true if executing @program reinitializes domain transition,
- * false otherwise.
+ * @domainname: Domainname to check.
  *
- * Caller holds tomoyo_read_lock().
+ * Returns the last word of @domainname.
  */
-static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
-                                        domainname,
-                                        const struct tomoyo_path_info *program,
-                                        const struct tomoyo_path_info *
-                                        last_name)
+static const char *tomoyo_last_word(const char *name)
 {
-       struct tomoyo_domain_initializer_entry *ptr;
-       bool flag = false;
-
-       list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
-               if (ptr->is_deleted)
-                       continue;
-               if (ptr->domainname) {
-                       if (!ptr->is_last_name) {
-                               if (ptr->domainname != domainname)
-                                       continue;
-                       } else {
-                               if (tomoyo_pathcmp(ptr->domainname, last_name))
-                                       continue;
-                       }
-               }
-               if (tomoyo_pathcmp(ptr->program, program))
-                       continue;
-               if (ptr->is_not) {
-                       flag = false;
-                       break;
-               }
-               flag = true;
-       }
-       return flag;
+        const char *cp = strrchr(name, ' ');
+        if (cp)
+                return cp + 1;
+        return name;
 }
 
-/*
- * tomoyo_domain_keeper_list is used for holding list of domainnames which
- * suppresses domain transition. Normally, a domainname is monotonically
- * getting longer. But sometimes, we want to suppress domain transition.
- * It would be convenient for us that programs executed from a login session
- * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
- * transition.
- *
- * An entry is added by
- *
- * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, any process which belongs to
- * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
- * unless explicitly specified by "initialize_domain" or "no_keep_domain".
- *
- * You may specify a program using "from" keyword.
- * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
- * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
- * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
- *
- * You may add "no_" prefix to "keep_domain".
- * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
- * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
- * cause "/usr/bin/passwd" to belong to
- * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
- * explicitly specified by "initialize_domain".
- */
-LIST_HEAD(tomoyo_domain_keeper_list);
+static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
+                                          const struct tomoyo_acl_head *b)
+{
+       const struct tomoyo_transition_control *p1 = container_of(a,
+                                                                 typeof(*p1),
+                                                                 head);
+       const struct tomoyo_transition_control *p2 = container_of(b,
+                                                                 typeof(*p2),
+                                                                 head);
+       return p1->type == p2->type && p1->is_last_name == p2->is_last_name
+               && p1->domainname == p2->domainname
+               && p1->program == p2->program;
+}
 
 /**
- * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
+ * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list.
  *
- * @domainname: The name of domain.
- * @program:    The name of program. May be NULL.
- * @is_not:     True if it is "no_keep_domain" entry.
+ * @domainname: The name of domain. Maybe NULL.
+ * @program:    The name of program. Maybe NULL.
+ * @type:       Type of transition.
  * @is_delete:  True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_domain_keeper_entry(const char *domainname,
-                                            const char *program,
-                                            const bool is_not,
-                                            const bool is_delete)
+static int tomoyo_update_transition_control_entry(const char *domainname,
+                                                 const char *program,
+                                                 const u8 type,
+                                                 const bool is_delete)
 {
-       struct tomoyo_domain_keeper_entry *ptr;
-       struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
+       struct tomoyo_transition_control e = { .type = type };
        int error = is_delete ? -ENOENT : -ENOMEM;
-
-       if (!tomoyo_is_domain_def(domainname) &&
-           tomoyo_is_correct_path(domainname, 1, -1, -1))
-               e.is_last_name = true;
-       else if (!tomoyo_is_correct_domain(domainname))
-               return -EINVAL;
        if (program) {
-               if (!tomoyo_is_correct_path(program, 1, -1, -1))
+               if (!tomoyo_correct_path(program))
                        return -EINVAL;
                e.program = tomoyo_get_name(program);
                if (!e.program)
                        goto out;
        }
-       e.domainname = tomoyo_get_name(domainname);
-       if (!e.domainname)
-               goto out;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
-               if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
-                       continue;
-               ptr->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_domain_keeper_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list,
-                                         &tomoyo_domain_keeper_list);
-                       error = 0;
+       if (domainname) {
+               if (!tomoyo_correct_domain(domainname)) {
+                       if (!tomoyo_correct_path(domainname))
+                               goto out;
+                       e.is_last_name = true;
                }
+               e.domainname = tomoyo_get_name(domainname);
+               if (!e.domainname)
+                       goto out;
        }
-       mutex_unlock(&tomoyo_policy_lock);
+       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                    &tomoyo_policy_list
+                                    [TOMOYO_ID_TRANSITION_CONTROL],
+                                    tomoyo_same_transition_control);
  out:
        tomoyo_put_name(e.domainname);
        tomoyo_put_name(e.program);
@@ -385,219 +207,133 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
 }
 
 /**
- * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
+ * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
  *
  * @data:      String to parse.
- * @is_not:    True if it is "no_keep_domain" entry.
  * @is_delete: True if it is a delete request.
+ * @type:      Type of this entry.
  *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
-                                     const bool is_delete)
-{
-       char *cp = strstr(data, " from ");
-
-       if (cp) {
-               *cp = '\0';
-               return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
-                                                        is_delete);
-       }
-       return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
-}
-
-/**
- * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
+ * Returns 0 on success, negative value otherwise.
  */
-bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+                                   const u8 type)
 {
-       struct list_head *pos;
-       bool done = true;
-
-       list_for_each_cookie(pos, head->read_var2,
-                            &tomoyo_domain_keeper_list) {
-               struct tomoyo_domain_keeper_entry *ptr;
-               const char *no;
-               const char *from = "";
-               const char *program = "";
-
-               ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
-               if (ptr->is_deleted)
-                       continue;
-               no = ptr->is_not ? "no_" : "";
-               if (ptr->program) {
-                       from = " from ";
-                       program = ptr->program->name;
-               }
-               done = tomoyo_io_printf(head,
-                                       "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
-                                       "%s%s%s\n", no, program, from,
-                                       ptr->domainname->name);
-               if (!done)
-                       break;
+       char *domainname = strstr(data, " from ");
+       if (domainname) {
+               *domainname = '\0';
+               domainname += 6;
+       } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
+                  type == TOMOYO_TRANSITION_CONTROL_KEEP) {
+               domainname = data;
+               data = NULL;
        }
-       return done;
+       return tomoyo_update_transition_control_entry(domainname, data, type,
+                                                     is_delete);
 }
 
 /**
- * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
+ * tomoyo_transition_type - Get domain transition type.
  *
  * @domainname: The name of domain.
  * @program:    The name of program.
- * @last_name:  The last component of @domainname.
  *
- * Returns true if executing @program supresses domain transition,
- * false otherwise.
+ * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
+ * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
+ * @program suppresses domain transition, others otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
-                                   const struct tomoyo_path_info *program,
-                                   const struct tomoyo_path_info *last_name)
+static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
+                                const struct tomoyo_path_info *program)
 {
-       struct tomoyo_domain_keeper_entry *ptr;
-       bool flag = false;
-
-       list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
-               if (ptr->is_deleted)
-                       continue;
-               if (!ptr->is_last_name) {
-                       if (ptr->domainname != domainname)
+       const struct tomoyo_transition_control *ptr;
+       const char *last_name = tomoyo_last_word(domainname->name);
+       u8 type;
+       for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
+ next:
+               list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+                                       [TOMOYO_ID_TRANSITION_CONTROL],
+                                       head.list) {
+                       if (ptr->head.is_deleted || ptr->type != type)
                                continue;
-               } else {
-                       if (tomoyo_pathcmp(ptr->domainname, last_name))
+                       if (ptr->domainname) {
+                               if (!ptr->is_last_name) {
+                                       if (ptr->domainname != domainname)
+                                               continue;
+                               } else {
+                                       /*
+                                        * Use direct strcmp() since this is
+                                        * unlikely used.
+                                        */
+                                       if (strcmp(ptr->domainname->name,
+                                                  last_name))
+                                               continue;
+                               }
+                       }
+                       if (ptr->program &&
+                           tomoyo_pathcmp(ptr->program, program))
                                continue;
+                       if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
+                               /*
+                                * Do not check for initialize_domain if
+                                * no_initialize_domain matched.
+                                */
+                               type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
+                               goto next;
+                       }
+                       goto done;
                }
-               if (ptr->program && tomoyo_pathcmp(ptr->program, program))
-                       continue;
-               if (ptr->is_not) {
-                       flag = false;
-                       break;
-               }
-               flag = true;
        }
-       return flag;
+ done:
+       return type;
 }
 
-/*
- * tomoyo_alias_list is used for holding list of symlink's pathnames which are
- * allowed to be passed to an execve() request. Normally, the domainname which
- * the current process will belong to after execve() succeeds is calculated
- * using dereferenced pathnames. But some programs behave differently depending
- * on the name passed to argv[0]. For busybox, calculating domainname using
- * dereferenced pathnames will cause all programs in the busybox to belong to
- * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
- * pathname for checking execve()'s permission and calculating domainname which
- * the current process will belong to after execve() succeeds.
- *
- * An entry is added by
- *
- * # echo 'alias /bin/busybox /bin/cat' > \
- *                            /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete alias /bin/busybox /bin/cat' > \
- *                            /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
- * of /bin/cat is requested, permission is checked for /bin/cat rather than
- * /bin/busybox and domainname which the current process will belong to after
- * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
- */
-LIST_HEAD(tomoyo_alias_list);
+static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
+                                  const struct tomoyo_acl_head *b)
+{
+       const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head);
+       const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head);
+       return p1->original_name == p2->original_name &&
+               p1->aggregated_name == p2->aggregated_name;
+}
 
 /**
- * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
+ * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list.
  *
- * @original_name: The original program's real name.
- * @aliased_name:  The symbolic program's symbolic link's name.
- * @is_delete:     True if it is a delete request.
+ * @original_name:   The original program's name.
+ * @aggregated_name: The program name to use.
+ * @is_delete:       True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_alias_entry(const char *original_name,
-                                    const char *aliased_name,
-                                    const bool is_delete)
+static int tomoyo_update_aggregator_entry(const char *original_name,
+                                         const char *aggregated_name,
+                                         const bool is_delete)
 {
-       struct tomoyo_alias_entry *ptr;
-       struct tomoyo_alias_entry e = { };
+       struct tomoyo_aggregator e = { };
        int error = is_delete ? -ENOENT : -ENOMEM;
 
-       if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
-           !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
-               return -EINVAL; /* No patterns allowed. */
+       if (!tomoyo_correct_path(original_name) ||
+           !tomoyo_correct_path(aggregated_name))
+               return -EINVAL;
        e.original_name = tomoyo_get_name(original_name);
-       e.aliased_name = tomoyo_get_name(aliased_name);
-       if (!e.original_name || !e.aliased_name)
+       e.aggregated_name = tomoyo_get_name(aggregated_name);
+       if (!e.original_name || !e.aggregated_name ||
+           e.aggregated_name->is_patterned) /* No patterns allowed. */
                goto out;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
-               if (!tomoyo_is_same_alias_entry(ptr, &e))
-                       continue;
-               ptr->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_alias_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
+       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                    &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR],
+                                    tomoyo_same_aggregator);
  out:
        tomoyo_put_name(e.original_name);
-       tomoyo_put_name(e.aliased_name);
+       tomoyo_put_name(e.aggregated_name);
        return error;
 }
 
 /**
- * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
-{
-       struct list_head *pos;
-       bool done = true;
-
-       list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
-               struct tomoyo_alias_entry *ptr;
-
-               ptr = list_entry(pos, struct tomoyo_alias_entry, list);
-               if (ptr->is_deleted)
-                       continue;
-               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
-                                       ptr->original_name->name,
-                                       ptr->aliased_name->name);
-               if (!done)
-                       break;
-       }
-       return done;
-}
-
-/**
- * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
+ * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -606,18 +342,18 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_alias_policy(char *data, const bool is_delete)
+int tomoyo_write_aggregator(char *data, const bool is_delete)
 {
        char *cp = strchr(data, ' ');
 
        if (!cp)
                return -EINVAL;
        *cp++ = '\0';
-       return tomoyo_update_alias_entry(data, cp, is_delete);
+       return tomoyo_update_aggregator_entry(data, cp, is_delete);
 }
 
 /**
- * tomoyo_find_or_assign_new_domain - Create a domain.
+ * tomoyo_assign_domain - Create a domain.
  *
  * @domainname: The name of domain.
  * @profile:    Profile number to assign if the domain was newly created.
@@ -626,16 +362,15 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
  *
  * Caller holds tomoyo_read_lock().
  */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-                                                           domainname,
-                                                           const u8 profile)
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+                                               const u8 profile)
 {
        struct tomoyo_domain_info *entry;
        struct tomoyo_domain_info *domain = NULL;
        const struct tomoyo_path_info *saved_domainname;
        bool found = false;
 
-       if (!tomoyo_is_correct_domain(domainname))
+       if (!tomoyo_correct_domain(domainname))
                return NULL;
        saved_domainname = tomoyo_get_name(domainname);
        if (!saved_domainname)
@@ -678,116 +413,118 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
  */
 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
-       /*
-        * This function assumes that the size of buffer returned by
-        * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
-        */
-       struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
+       struct tomoyo_request_info r;
+       char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
        struct tomoyo_domain_info *old_domain = tomoyo_domain();
        struct tomoyo_domain_info *domain = NULL;
-       const char *old_domain_name = old_domain->domainname->name;
        const char *original_name = bprm->filename;
-       char *new_domain_name = NULL;
-       char *real_program_name = NULL;
-       char *symlink_program_name = NULL;
-       const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
-       const bool is_enforce = (mode == 3);
+       u8 mode;
+       bool is_enforce;
        int retval = -ENOMEM;
-       struct tomoyo_path_info r; /* real name */
-       struct tomoyo_path_info s; /* symlink name */
-       struct tomoyo_path_info l; /* last name */
-       static bool initialized;
+       bool need_kfree = false;
+       struct tomoyo_path_info rn = { }; /* real name */
 
+       mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+       is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
        if (!tmp)
                goto out;
 
-       if (!initialized) {
-               /*
-                * Built-in initializers. This is needed because policies are
-                * not loaded until starting /sbin/init.
-                */
-               tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
-                                                      false, false);
-               tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
-                                                      false, false);
-               initialized = true;
+ retry:
+       if (need_kfree) {
+               kfree(rn.name);
+               need_kfree = false;
        }
-
-       /* Get tomoyo_realpath of program. */
+       /* Get symlink's pathname of program. */
        retval = -ENOENT;
-       /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
-       real_program_name = tomoyo_realpath(original_name);
-       if (!real_program_name)
-               goto out;
-       /* Get tomoyo_realpath of symbolic link. */
-       symlink_program_name = tomoyo_realpath_nofollow(original_name);
-       if (!symlink_program_name)
+       rn.name = tomoyo_realpath_nofollow(original_name);
+       if (!rn.name)
                goto out;
-
-       r.name = real_program_name;
-       tomoyo_fill_path_info(&r);
-       s.name = symlink_program_name;
-       tomoyo_fill_path_info(&s);
-       l.name = tomoyo_get_last_name(old_domain);
-       tomoyo_fill_path_info(&l);
-
-       /* Check 'alias' directive. */
-       if (tomoyo_pathcmp(&r, &s)) {
-               struct tomoyo_alias_entry *ptr;
-               /* Is this program allowed to be called via symbolic links? */
-               list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
-                       if (ptr->is_deleted ||
-                           tomoyo_pathcmp(&r, ptr->original_name) ||
-                           tomoyo_pathcmp(&s, ptr->aliased_name))
+       tomoyo_fill_path_info(&rn);
+       need_kfree = true;
+
+       /* Check 'aggregator' directive. */
+       {
+               struct tomoyo_aggregator *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+                                       [TOMOYO_ID_AGGREGATOR], head.list) {
+                       if (ptr->head.is_deleted ||
+                           !tomoyo_path_matches_pattern(&rn,
+                                                        ptr->original_name))
                                continue;
-                       memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
-                       strncpy(real_program_name, ptr->aliased_name->name,
-                               TOMOYO_MAX_PATHNAME_LEN - 1);
-                       tomoyo_fill_path_info(&r);
+                       kfree(rn.name);
+                       need_kfree = false;
+                       /* This is OK because it is read only. */
+                       rn = *ptr->aggregated_name;
                        break;
                }
        }
 
        /* Check execute permission. */
-       retval = tomoyo_check_exec_perm(old_domain, &r);
+       retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
+       if (retval == TOMOYO_RETRY_REQUEST)
+               goto retry;
        if (retval < 0)
                goto out;
+       /*
+        * To be able to specify domainnames with wildcards, use the
+        * pathname specified in the policy (which may contain
+        * wildcard) rather than the pathname passed to execve()
+        * (which never contains wildcard).
+        */
+       if (r.param.path.matched_path) {
+               if (need_kfree)
+                       kfree(rn.name);
+               need_kfree = false;
+               /* This is OK because it is read only. */
+               rn = *r.param.path.matched_path;
+       }
 
-       new_domain_name = tmp->buffer;
-       if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
+       /* Calculate domain to transit to. */
+       switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
+       case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
                /* Transit to the child of tomoyo_kernel_domain domain. */
-               snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
-                        TOMOYO_ROOT_NAME " " "%s", real_program_name);
-       } else if (old_domain == &tomoyo_kernel_domain &&
-                  !tomoyo_policy_loaded) {
-               /*
-                * Needn't to transit from kernel domain before starting
-                * /sbin/init. But transit from kernel domain if executing
-                * initializers because they might start before /sbin/init.
-                */
-               domain = old_domain;
-       } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
+               snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
+                        "%s", rn.name);
+               break;
+       case TOMOYO_TRANSITION_CONTROL_KEEP:
                /* Keep current domain. */
                domain = old_domain;
-       } else {
-               /* Normal domain transition. */
-               snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
-                        "%s %s", old_domain_name, real_program_name);
+               break;
+       default:
+               if (old_domain == &tomoyo_kernel_domain &&
+                   !tomoyo_policy_loaded) {
+                       /*
+                        * Needn't to transit from kernel domain before
+                        * starting /sbin/init. But transit from kernel domain
+                        * if executing initializers because they might start
+                        * before /sbin/init.
+                        */
+                       domain = old_domain;
+               } else {
+                       /* Normal domain transition. */
+                       snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+                                old_domain->domainname->name, rn.name);
+               }
+               break;
        }
-       if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
+       if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
                goto done;
-       domain = tomoyo_find_domain(new_domain_name);
+       domain = tomoyo_find_domain(tmp);
        if (domain)
                goto done;
-       if (is_enforce)
-               goto done;
-       domain = tomoyo_find_or_assign_new_domain(new_domain_name,
-                                                 old_domain->profile);
+       if (is_enforce) {
+               int error = tomoyo_supervisor(&r, "# wants to create domain\n"
+                                             "%s\n", tmp);
+               if (error == TOMOYO_RETRY_REQUEST)
+                       goto retry;
+               if (error < 0)
+                       goto done;
+       }
+       domain = tomoyo_assign_domain(tmp, old_domain->profile);
  done:
        if (domain)
                goto out;
-       printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
-              new_domain_name);
+       printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
        if (is_enforce)
                retval = -EPERM;
        else
@@ -798,8 +535,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        /* Update reference count on "struct tomoyo_domain_info". */
        atomic_inc(&domain->users);
        bprm->cred->security = domain;
-       kfree(real_program_name);
-       kfree(symlink_program_name);
+       if (need_kfree)
+               kfree(rn.name);
        kfree(tmp);
        return retval;
 }
index 1c6f8238ec47a1866e74f80da1d2e6c120b69ff3..9d32f182301ee6cfcfdb4d18508a7b9773f275eb 100644 (file)
@@ -1,48 +1,88 @@
 /*
  * security/tomoyo/file.c
  *
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
+ * Pathname restriction functions.
  *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include "common.h"
 #include <linux/slab.h>
 
-/* Keyword array for single path operations. */
-static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
+/* Keyword array for operations with one pathname. */
+const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
        [TOMOYO_TYPE_READ_WRITE] = "read/write",
        [TOMOYO_TYPE_EXECUTE]    = "execute",
        [TOMOYO_TYPE_READ]       = "read",
        [TOMOYO_TYPE_WRITE]      = "write",
-       [TOMOYO_TYPE_CREATE]     = "create",
        [TOMOYO_TYPE_UNLINK]     = "unlink",
-       [TOMOYO_TYPE_MKDIR]      = "mkdir",
        [TOMOYO_TYPE_RMDIR]      = "rmdir",
-       [TOMOYO_TYPE_MKFIFO]     = "mkfifo",
-       [TOMOYO_TYPE_MKSOCK]     = "mksock",
-       [TOMOYO_TYPE_MKBLOCK]    = "mkblock",
-       [TOMOYO_TYPE_MKCHAR]     = "mkchar",
        [TOMOYO_TYPE_TRUNCATE]   = "truncate",
        [TOMOYO_TYPE_SYMLINK]    = "symlink",
        [TOMOYO_TYPE_REWRITE]    = "rewrite",
+       [TOMOYO_TYPE_CHROOT]     = "chroot",
+       [TOMOYO_TYPE_UMOUNT]     = "unmount",
+};
+
+/* Keyword array for operations with one pathname and three numbers. */
+const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
+       [TOMOYO_TYPE_MKBLOCK]    = "mkblock",
+       [TOMOYO_TYPE_MKCHAR]     = "mkchar",
+};
+
+/* Keyword array for operations with two pathnames. */
+const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
+       [TOMOYO_TYPE_LINK]       = "link",
+       [TOMOYO_TYPE_RENAME]     = "rename",
+       [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
+};
+
+/* Keyword array for operations with one pathname and one number. */
+const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+       [TOMOYO_TYPE_CREATE]     = "create",
+       [TOMOYO_TYPE_MKDIR]      = "mkdir",
+       [TOMOYO_TYPE_MKFIFO]     = "mkfifo",
+       [TOMOYO_TYPE_MKSOCK]     = "mksock",
        [TOMOYO_TYPE_IOCTL]      = "ioctl",
        [TOMOYO_TYPE_CHMOD]      = "chmod",
        [TOMOYO_TYPE_CHOWN]      = "chown",
        [TOMOYO_TYPE_CHGRP]      = "chgrp",
-       [TOMOYO_TYPE_CHROOT]     = "chroot",
-       [TOMOYO_TYPE_MOUNT]      = "mount",
-       [TOMOYO_TYPE_UMOUNT]     = "unmount",
 };
 
-/* Keyword array for double path operations. */
-static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
-       [TOMOYO_TYPE_LINK]    = "link",
-       [TOMOYO_TYPE_RENAME]  = "rename",
-       [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
+static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
+       [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
+       [TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
+       [TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
+       [TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
+       [TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
+       [TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
+       [TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
+       [TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
+       [TOMOYO_TYPE_REWRITE]    = TOMOYO_MAC_FILE_REWRITE,
+       [TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
+       [TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
+};
+
+static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
+       [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
+       [TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
+};
+
+static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+       [TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
+       [TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
+       [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
+};
+
+static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+       [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
+       [TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
+       [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
+       [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
+       [TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
+       [TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
+       [TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
+       [TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
 };
 
 void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
@@ -50,56 +90,45 @@ void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
        if (!ptr)
                return;
        if (ptr->is_group)
-               tomoyo_put_path_group(ptr->group);
+               tomoyo_put_group(ptr->group);
        else
                tomoyo_put_name(ptr->filename);
 }
 
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
-                              const struct tomoyo_name_union *ptr)
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+                         const struct tomoyo_name_union *ptr)
 {
        if (ptr->is_group)
-               return tomoyo_path_matches_group(name, ptr->group, 1);
-       return tomoyo_path_matches_pattern(name, ptr->filename);
+               return tomoyo_path_matches_group(name, ptr->group);
+       if (tomoyo_path_matches_pattern(name, ptr->filename))
+               return ptr->filename;
+       return NULL;
 }
 
-static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info
-                                             *name,
-                                             const struct tomoyo_name_union
-                                             *ptr, const bool may_use_pattern)
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
 {
-       if (ptr->is_group)
-               return tomoyo_path_matches_group(name, ptr->group,
-                                                may_use_pattern);
-       if (may_use_pattern || !ptr->filename->is_patterned)
-               return tomoyo_path_matches_pattern(name, ptr->filename);
-       return false;
+       if (ptr && ptr->is_group)
+               tomoyo_put_group(ptr->group);
 }
 
-/**
- * tomoyo_path2keyword - Get the name of single path operation.
- *
- * @operation: Type of operation.
- *
- * Returns the name of single path operation.
- */
-const char *tomoyo_path2keyword(const u8 operation)
+bool tomoyo_compare_number_union(const unsigned long value,
+                                const struct tomoyo_number_union *ptr)
 {
-       return (operation < TOMOYO_MAX_PATH_OPERATION)
-               ? tomoyo_path_keyword[operation] : NULL;
+       if (ptr->is_group)
+               return tomoyo_number_matches_group(value, value, ptr->group);
+       return value >= ptr->values[0] && value <= ptr->values[1];
 }
 
-/**
- * tomoyo_path22keyword - Get the name of double path operation.
- *
- * @operation: Type of operation.
- *
- * Returns the name of double path operation.
- */
-const char *tomoyo_path22keyword(const u8 operation)
+static void tomoyo_add_slash(struct tomoyo_path_info *buf)
 {
-       return (operation < TOMOYO_MAX_PATH2_OPERATION)
-               ? tomoyo_path2_keyword[operation] : NULL;
+       if (buf->is_dir)
+               return;
+       /*
+        * This is OK because tomoyo_encode() reserves space for appending "/".
+        */
+       strcat((char *) buf->name, "/");
+       tomoyo_fill_path_info(buf);
 }
 
 /**
@@ -121,69 +150,134 @@ static bool tomoyo_strendswith(const char *name, const char *tail)
 }
 
 /**
- * tomoyo_get_path - Get realpath.
+ * tomoyo_get_realpath - Get realpath.
  *
+ * @buf:  Pointer to "struct tomoyo_path_info".
  * @path: Pointer to "struct path".
  *
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
  */
-static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
+static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
 {
-       int error;
-       struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
-                                                        GFP_NOFS);
-
-       if (!buf)
-               return NULL;
-       /* Reserve one byte for appending "/". */
-       error = tomoyo_realpath_from_path2(path, buf->body,
-                                          sizeof(buf->body) - 2);
-       if (!error) {
-               buf->head.name = buf->body;
-               tomoyo_fill_path_info(&buf->head);
-               return &buf->head;
+       buf->name = tomoyo_realpath_from_path(path);
+       if (buf->name) {
+               tomoyo_fill_path_info(buf);
+               return true;
        }
-       kfree(buf);
-       return NULL;
+        return false;
 }
 
-static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
-                                  const char *filename2,
-                                  struct tomoyo_domain_info *const domain,
-                                  const bool is_delete);
-static int tomoyo_update_path_acl(const u8 type, const char *filename,
-                                 struct tomoyo_domain_info *const domain,
-                                 const bool is_delete);
-
-/*
- * tomoyo_globally_readable_list is used for holding list of pathnames which
- * are by default allowed to be open()ed for reading by any process.
+/**
+ * tomoyo_audit_path_log - Audit path request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
  *
- * An entry is added by
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
+{
+       const char *operation = tomoyo_path_keyword[r->param.path.operation];
+       const struct tomoyo_path_info *filename = r->param.path.filename;
+       if (r->granted)
+               return 0;
+       tomoyo_warn_log(r, "%s %s", operation, filename->name);
+       return tomoyo_supervisor(r, "allow_%s %s\n", operation,
+                                tomoyo_pattern(filename));
+}
+
+/**
+ * tomoyo_audit_path2_log - Audit path/path request log.
  *
- * # echo 'allow_read /lib/libc-2.5.so' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
+ * @r: Pointer to "struct tomoyo_request_info".
  *
- * and is deleted by
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
+{
+       const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
+       const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
+       const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
+       if (r->granted)
+               return 0;
+       tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
+                       filename2->name);
+       return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
+                                tomoyo_pattern(filename1),
+                                tomoyo_pattern(filename2));
+}
+
+/**
+ * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
  *
- * # echo 'delete allow_read /lib/libc-2.5.so' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
+ * @r: Pointer to "struct tomoyo_request_info".
  *
- * and all entries are retrieved by
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
+{
+       const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
+       const struct tomoyo_path_info *filename = r->param.mkdev.filename;
+       const unsigned int major = r->param.mkdev.major;
+       const unsigned int minor = r->param.mkdev.minor;
+       const unsigned int mode = r->param.mkdev.mode;
+       if (r->granted)
+               return 0;
+       tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
+                       major, minor);
+       return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
+                                tomoyo_pattern(filename), mode, major, minor);
+}
+
+/**
+ * tomoyo_audit_path_number_log - Audit path/number request log.
  *
- * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy
+ * @r:     Pointer to "struct tomoyo_request_info".
+ * @error: Error code.
  *
- * In the example above, any process is allowed to
- * open("/lib/libc-2.5.so", O_RDONLY).
- * One exception is, if the domain which current process belongs to is marked
- * as "ignore_global_allow_read", current process can't do so unless explicitly
- * given "allow_read /lib/libc-2.5.so" to the domain which current process
- * belongs to.
+ * Returns 0 on success, negative value otherwise.
  */
-LIST_HEAD(tomoyo_globally_readable_list);
+static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
+{
+       const u8 type = r->param.path_number.operation;
+       u8 radix;
+       const struct tomoyo_path_info *filename = r->param.path_number.filename;
+       const char *operation = tomoyo_path_number_keyword[type];
+       char buffer[64];
+       if (r->granted)
+               return 0;
+       switch (type) {
+       case TOMOYO_TYPE_CREATE:
+       case TOMOYO_TYPE_MKDIR:
+       case TOMOYO_TYPE_MKFIFO:
+       case TOMOYO_TYPE_MKSOCK:
+       case TOMOYO_TYPE_CHMOD:
+               radix = TOMOYO_VALUE_TYPE_OCTAL;
+               break;
+       case TOMOYO_TYPE_IOCTL:
+               radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
+               break;
+       default:
+               radix = TOMOYO_VALUE_TYPE_DECIMAL;
+               break;
+       }
+       tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
+                          radix);
+       tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
+       return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
+                                tomoyo_pattern(filename), buffer);
+}
+
+static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
+                                         const struct tomoyo_acl_head *b)
+{
+       return container_of(a, struct tomoyo_readable_file,
+                           head)->filename ==
+               container_of(b, struct tomoyo_readable_file,
+                            head)->filename;
+}
 
 /**
- * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
+ * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
  *
  * @filename:  Filename unconditionally permitted to open() for reading.
  * @is_delete: True if it is a delete request.
@@ -195,41 +289,24 @@ LIST_HEAD(tomoyo_globally_readable_list);
 static int tomoyo_update_globally_readable_entry(const char *filename,
                                                 const bool is_delete)
 {
-       struct tomoyo_globally_readable_file_entry *ptr;
-       struct tomoyo_globally_readable_file_entry e = { };
-       int error = is_delete ? -ENOENT : -ENOMEM;
+       struct tomoyo_readable_file e = { };
+       int error;
 
-       if (!tomoyo_is_correct_path(filename, 1, 0, -1))
+       if (!tomoyo_correct_word(filename))
                return -EINVAL;
        e.filename = tomoyo_get_name(filename);
        if (!e.filename)
                return -ENOMEM;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
-               if (ptr->filename != e.filename)
-                       continue;
-               ptr->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_globally_readable_file_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list,
-                                         &tomoyo_globally_readable_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
- out:
+       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                    &tomoyo_policy_list
+                                    [TOMOYO_ID_GLOBALLY_READABLE],
+                                    tomoyo_same_globally_readable);
        tomoyo_put_name(e.filename);
        return error;
 }
 
 /**
- * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
+ * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
  *
  * @filename: The filename to check.
  *
@@ -237,14 +314,15 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
+static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
                                             filename)
 {
-       struct tomoyo_globally_readable_file_entry *ptr;
+       struct tomoyo_readable_file *ptr;
        bool found = false;
 
-       list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
-               if (!ptr->is_deleted &&
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+                               [TOMOYO_ID_GLOBALLY_READABLE], head.list) {
+               if (!ptr->head.is_deleted &&
                    tomoyo_path_matches_pattern(filename, ptr->filename)) {
                        found = true;
                        break;
@@ -254,7 +332,7 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
 }
 
 /**
- * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
+ * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -263,74 +341,20 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
+int tomoyo_write_globally_readable(char *data, const bool is_delete)
 {
        return tomoyo_update_globally_readable_entry(data, is_delete);
 }
 
-/**
- * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
+                               const struct tomoyo_acl_head *b)
 {
-       struct list_head *pos;
-       bool done = true;
-
-       list_for_each_cookie(pos, head->read_var2,
-                            &tomoyo_globally_readable_list) {
-               struct tomoyo_globally_readable_file_entry *ptr;
-               ptr = list_entry(pos,
-                                struct tomoyo_globally_readable_file_entry,
-                                list);
-               if (ptr->is_deleted)
-                       continue;
-               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
-                                       ptr->filename->name);
-               if (!done)
-                       break;
-       }
-       return done;
+       return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
+               container_of(b, struct tomoyo_no_pattern, head)->pattern;
 }
 
-/* tomoyo_pattern_list is used for holding list of pathnames which are used for
- * converting pathnames to pathname patterns during learning mode.
- *
- * An entry is added by
- *
- * # echo 'file_pattern /proc/\$/mounts' > \
- *                             /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete file_pattern /proc/\$/mounts' > \
- *                             /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if a process which belongs to a domain which is in
- * learning mode requested open("/proc/1/mounts", O_RDONLY),
- * "allow_read /proc/\$/mounts" is automatically added to the domain which that
- * process belongs to.
- *
- * It is not a desirable behavior that we have to use /proc/\$/ instead of
- * /proc/self/ when current process needs to access only current process's
- * information. As of now, LSM version of TOMOYO is using __d_path() for
- * calculating pathname. Non LSM version of TOMOYO is using its own function
- * which pretends as if /proc/self/ is not a symlink; so that we can forbid
- * current process from accessing other process's information.
- */
-LIST_HEAD(tomoyo_pattern_list);
-
 /**
- * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
+ * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
  *
  * @pattern:   Pathname pattern.
  * @is_delete: True if it is a delete request.
@@ -342,39 +366,23 @@ LIST_HEAD(tomoyo_pattern_list);
 static int tomoyo_update_file_pattern_entry(const char *pattern,
                                            const bool is_delete)
 {
-       struct tomoyo_pattern_entry *ptr;
-       struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
-       int error = is_delete ? -ENOENT : -ENOMEM;
+       struct tomoyo_no_pattern e = { };
+       int error;
 
+       if (!tomoyo_correct_word(pattern))
+               return -EINVAL;
+       e.pattern = tomoyo_get_name(pattern);
        if (!e.pattern)
-               return error;
-       if (!e.pattern->is_patterned)
-               goto out;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
-               if (e.pattern != ptr->pattern)
-                       continue;
-               ptr->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_pattern_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
- out:
+               return -ENOMEM;
+       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                    &tomoyo_policy_list[TOMOYO_ID_PATTERN],
+                                    tomoyo_same_pattern);
        tomoyo_put_name(e.pattern);
        return error;
 }
 
 /**
- * tomoyo_get_file_pattern - Get patterned pathname.
+ * tomoyo_pattern - Get patterned pathname.
  *
  * @filename: The filename to find patterned pathname.
  *
@@ -382,14 +390,14 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
  *
  * Caller holds tomoyo_read_lock().
  */
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
 {
-       struct tomoyo_pattern_entry *ptr;
+       struct tomoyo_no_pattern *ptr;
        const struct tomoyo_path_info *pattern = NULL;
 
-       list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
-               if (ptr->is_deleted)
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
+                               head.list) {
+               if (ptr->head.is_deleted)
                        continue;
                if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
                        continue;
@@ -403,11 +411,11 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
        }
        if (pattern)
                filename = pattern;
-       return filename;
+       return filename->name;
 }
 
 /**
- * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
+ * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -416,71 +424,21 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_pattern_policy(char *data, const bool is_delete)
+int tomoyo_write_pattern(char *data, const bool is_delete)
 {
        return tomoyo_update_file_pattern_entry(data, is_delete);
 }
 
-/**
- * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
+static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
+                                  const struct tomoyo_acl_head *b)
 {
-       struct list_head *pos;
-       bool done = true;
-
-       list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
-               struct tomoyo_pattern_entry *ptr;
-               ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
-               if (ptr->is_deleted)
-                       continue;
-               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
-                                       "%s\n", ptr->pattern->name);
-               if (!done)
-                       break;
-       }
-       return done;
+       return container_of(a, struct tomoyo_no_rewrite, head)->pattern
+               == container_of(b, struct tomoyo_no_rewrite, head)
+               ->pattern;
 }
 
-/*
- * tomoyo_no_rewrite_list is used for holding list of pathnames which are by
- * default forbidden to modify already written content of a file.
- *
- * An entry is added by
- *
- * # echo 'deny_rewrite /var/log/messages' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete deny_rewrite /var/log/messages' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if a process requested to rewrite /var/log/messages ,
- * the process can't rewrite unless the domain which that process belongs to
- * has "allow_rewrite /var/log/messages" entry.
- *
- * It is not a desirable behavior that we have to add "\040(deleted)" suffix
- * when we want to allow rewriting already unlink()ed file. As of now,
- * LSM version of TOMOYO is using __d_path() for calculating pathname.
- * Non LSM version of TOMOYO is using its own function which doesn't append
- * " (deleted)" suffix if the file is already unlink()ed; so that we don't
- * need to worry whether the file is already unlink()ed or not.
- */
-LIST_HEAD(tomoyo_no_rewrite_list);
-
 /**
- * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
+ * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
  *
  * @pattern:   Pathname pattern that are not rewritable by default.
  * @is_delete: True if it is a delete request.
@@ -492,41 +450,23 @@ LIST_HEAD(tomoyo_no_rewrite_list);
 static int tomoyo_update_no_rewrite_entry(const char *pattern,
                                          const bool is_delete)
 {
-       struct tomoyo_no_rewrite_entry *ptr;
-       struct tomoyo_no_rewrite_entry e = { };
-       int error = is_delete ? -ENOENT : -ENOMEM;
+       struct tomoyo_no_rewrite e = { };
+       int error;
 
-       if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
+       if (!tomoyo_correct_word(pattern))
                return -EINVAL;
        e.pattern = tomoyo_get_name(pattern);
        if (!e.pattern)
-               return error;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
-               if (ptr->pattern != e.pattern)
-                       continue;
-               ptr->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_no_rewrite_entry *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list,
-                                         &tomoyo_no_rewrite_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
- out:
+               return -ENOMEM;
+       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                    &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
+                                    tomoyo_same_no_rewrite);
        tomoyo_put_name(e.pattern);
        return error;
 }
 
 /**
- * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
+ * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
  *
  * @filename: Filename to check.
  *
@@ -535,13 +475,14 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
+static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
 {
-       struct tomoyo_no_rewrite_entry *ptr;
+       struct tomoyo_no_rewrite *ptr;
        bool found = false;
 
-       list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
-               if (ptr->is_deleted)
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
+                               head.list) {
+               if (ptr->head.is_deleted)
                        continue;
                if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
                        continue;
@@ -552,7 +493,7 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
 }
 
 /**
- * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
+ * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -561,214 +502,103 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
+int tomoyo_write_no_rewrite(char *data, const bool is_delete)
 {
        return tomoyo_update_no_rewrite_entry(data, is_delete);
 }
 
-/**
- * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
+                                 const struct tomoyo_acl_info *ptr)
 {
-       struct list_head *pos;
-       bool done = true;
-
-       list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
-               struct tomoyo_no_rewrite_entry *ptr;
-               ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
-               if (ptr->is_deleted)
-                       continue;
-               done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
-                                       "%s\n", ptr->pattern->name);
-               if (!done)
-                       break;
+       const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
+                                                        head);
+       if (acl->perm & (1 << r->param.path.operation)) {
+               r->param.path.matched_path =
+                       tomoyo_compare_name_union(r->param.path.filename,
+                                                 &acl->name);
+               return r->param.path.matched_path != NULL;
        }
-       return done;
+       return false;
 }
 
-/**
- * tomoyo_update_file_acl - Update file's read/write/execute ACL.
- *
- * @filename:  Filename.
- * @perm:      Permission (between 1 to 7).
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * This is legacy support interface for older policy syntax.
- * Current policy syntax uses "allow_read/write" instead of "6",
- * "allow_read" instead of "4", "allow_write" instead of "2",
- * "allow_execute" instead of "1".
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_file_acl(const char *filename, u8 perm,
-                                 struct tomoyo_domain_info * const domain,
-                                 const bool is_delete)
+static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
+                                        const struct tomoyo_acl_info *ptr)
 {
-       if (perm > 7 || !perm) {
-               printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
-                      __func__, perm, filename);
-               return -EINVAL;
-       }
-       if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
-               /*
-                * Only 'allow_mkdir' and 'allow_rmdir' are valid for
-                * directory permissions.
-                */
-               return 0;
-       if (perm & 4)
-               tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
-                                      is_delete);
-       if (perm & 2)
-               tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
-                                      is_delete);
-       if (perm & 1)
-               tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
-                                      is_delete);
-       return 0;
+       const struct tomoyo_path_number_acl *acl =
+               container_of(ptr, typeof(*acl), head);
+       return (acl->perm & (1 << r->param.path_number.operation)) &&
+               tomoyo_compare_number_union(r->param.path_number.number,
+                                           &acl->number) &&
+               tomoyo_compare_name_union(r->param.path_number.filename,
+                                         &acl->name);
 }
 
-/**
- * tomoyo_path_acl2 - Check permission for single path operation.
- *
- * @domain:          Pointer to "struct tomoyo_domain_info".
- * @filename:        Filename to check.
- * @perm:            Permission.
- * @may_use_pattern: True if patterned ACL is permitted.
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
-                           const struct tomoyo_path_info *filename,
-                           const u32 perm, const bool may_use_pattern)
+static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
+                                  const struct tomoyo_acl_info *ptr)
 {
-       struct tomoyo_acl_info *ptr;
-       int error = -EPERM;
-
-       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-               struct tomoyo_path_acl *acl;
-               if (ptr->type != TOMOYO_TYPE_PATH_ACL)
-                       continue;
-               acl = container_of(ptr, struct tomoyo_path_acl, head);
-               if (perm <= 0xFFFF) {
-                       if (!(acl->perm & perm))
-                               continue;
-               } else {
-                       if (!(acl->perm_high & (perm >> 16)))
-                               continue;
-               }
-               if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
-                                                       may_use_pattern))
-                       continue;
-               error = 0;
-               break;
-       }
-       return error;
+       const struct tomoyo_path2_acl *acl =
+               container_of(ptr, typeof(*acl), head);
+       return (acl->perm & (1 << r->param.path2.operation)) &&
+               tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
+               && tomoyo_compare_name_union(r->param.path2.filename2,
+                                            &acl->name2);
 }
 
-/**
- * tomoyo_check_file_acl - Check permission for opening files.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @filename:  Filename to check.
- * @operation: Mode ("read" or "write" or "read/write" or "execute").
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
-                                const struct tomoyo_path_info *filename,
-                                const u8 operation)
+static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
+                               const struct tomoyo_acl_info *ptr)
 {
-       u32 perm = 0;
-
-       if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
-               return 0;
-       if (operation == 6)
-               perm = 1 << TOMOYO_TYPE_READ_WRITE;
-       else if (operation == 4)
-               perm = 1 << TOMOYO_TYPE_READ;
-       else if (operation == 2)
-               perm = 1 << TOMOYO_TYPE_WRITE;
-       else if (operation == 1)
-               perm = 1 << TOMOYO_TYPE_EXECUTE;
-       else
-               BUG();
-       return tomoyo_path_acl2(domain, filename, perm, operation != 1);
+       const struct tomoyo_mkdev_acl *acl =
+               container_of(ptr, typeof(*acl), head);
+       return (acl->perm & (1 << r->param.mkdev.operation)) &&
+               tomoyo_compare_number_union(r->param.mkdev.mode,
+                                           &acl->mode) &&
+               tomoyo_compare_number_union(r->param.mkdev.major,
+                                           &acl->major) &&
+               tomoyo_compare_number_union(r->param.mkdev.minor,
+                                           &acl->minor) &&
+               tomoyo_compare_name_union(r->param.mkdev.filename,
+                                         &acl->name);
 }
 
-/**
- * tomoyo_check_file_perm2 - Check permission for opening files.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @filename:  Filename to check.
- * @perm:      Mode ("read" or "write" or "read/write" or "execute").
- * @operation: Operation name passed used for verbose mode.
- * @mode:      Access control mode.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
-                                  const struct tomoyo_path_info *filename,
-                                  const u8 perm, const char *operation,
-                                  const u8 mode)
+static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
+                                const struct tomoyo_acl_info *b)
 {
-       const bool is_enforce = (mode == 3);
-       const char *msg = "<unknown>";
-       int error = 0;
+       const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
+       const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
+       return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+               tomoyo_same_name_union(&p1->name, &p2->name);
+}
 
-       if (!filename)
-               return 0;
-       error = tomoyo_check_file_acl(domain, filename, perm);
-       if (error && perm == 4 && !domain->ignore_global_allow_read
-           && tomoyo_is_globally_readable_file(filename))
-               error = 0;
-       if (perm == 6)
-               msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE);
-       else if (perm == 4)
-               msg = tomoyo_path2keyword(TOMOYO_TYPE_READ);
-       else if (perm == 2)
-               msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE);
-       else if (perm == 1)
-               msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE);
-       else
-               BUG();
-       if (!error)
-               return 0;
-       if (tomoyo_verbose_mode(domain))
-               printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
-                      "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
-                      filename->name, tomoyo_get_last_name(domain));
-       if (is_enforce)
-               return error;
-       if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-               /* Don't use patterns for execute permission. */
-               const struct tomoyo_path_info *patterned_file = (perm != 1) ?
-                       tomoyo_get_file_pattern(filename) : filename;
-               tomoyo_update_file_acl(patterned_file->name, perm,
-                                      domain, false);
+static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
+                                 struct tomoyo_acl_info *b,
+                                 const bool is_delete)
+{
+       u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
+               ->perm;
+       u16 perm = *a_perm;
+       const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
+       if (is_delete) {
+               perm &= ~b_perm;
+               if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
+                       perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
+               else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+                       perm &= ~TOMOYO_RW_MASK;
+       } else {
+               perm |= b_perm;
+               if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
+                       perm |= (1 << TOMOYO_TYPE_READ_WRITE);
+               else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+                       perm |= TOMOYO_RW_MASK;
        }
-       return 0;
+       *a_perm = perm;
+       return !perm;
 }
 
 /**
- * tomoyo_write_file_policy - Update file related list.
+ * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
  *
- * @data:      String to parse.
+ * @type:      Type of operation.
+ * @filename:  Filename.
  * @domain:    Pointer to "struct tomoyo_domain_info".
  * @is_delete: True if it is a delete request.
  *
@@ -776,48 +606,65 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
-                            const bool is_delete)
+static int tomoyo_update_path_acl(const u8 type, const char *filename,
+                                 struct tomoyo_domain_info * const domain,
+                                 const bool is_delete)
 {
-       char *filename = strchr(data, ' ');
-       char *filename2;
-       unsigned int perm;
-       u8 type;
-
-       if (!filename)
+       struct tomoyo_path_acl e = {
+               .head.type = TOMOYO_TYPE_PATH_ACL,
+               .perm = 1 << type
+       };
+       int error;
+       if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
+               e.perm |= TOMOYO_RW_MASK;
+       if (!tomoyo_parse_name_union(filename, &e.name))
                return -EINVAL;
-       *filename++ = '\0';
-       if (sscanf(data, "%u", &perm) == 1)
-               return tomoyo_update_file_acl(filename, (u8) perm, domain,
-                                             is_delete);
-       if (strncmp(data, "allow_", 6))
-               goto out;
-       data += 6;
-       for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
-               if (strcmp(data, tomoyo_path_keyword[type]))
-                       continue;
-               return tomoyo_update_path_acl(type, filename, domain,
-                                             is_delete);
-       }
-       filename2 = strchr(filename, ' ');
-       if (!filename2)
-               goto out;
-       *filename2++ = '\0';
-       for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
-               if (strcmp(data, tomoyo_path2_keyword[type]))
-                       continue;
-               return tomoyo_update_path2_acl(type, filename, filename2,
-                                              domain, is_delete);
-       }
- out:
-       return -EINVAL;
+       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+                                    tomoyo_same_path_acl,
+                                    tomoyo_merge_path_acl);
+       tomoyo_put_name_union(&e.name);
+       return error;
+}
+
+static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
+                                        const struct tomoyo_acl_info *b)
+{
+       const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
+                                                               head);
+       const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
+                                                               head);
+       return tomoyo_same_acl_head(&p1->head, &p2->head)
+               && tomoyo_same_name_union(&p1->name, &p2->name)
+               && tomoyo_same_number_union(&p1->mode, &p2->mode)
+               && tomoyo_same_number_union(&p1->major, &p2->major)
+               && tomoyo_same_number_union(&p1->minor, &p2->minor);
+}
+
+static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
+                                         struct tomoyo_acl_info *b,
+                                         const bool is_delete)
+{
+       u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
+                                        head)->perm;
+       u8 perm = *a_perm;
+       const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
+               ->perm;
+       if (is_delete)
+               perm &= ~b_perm;
+       else
+               perm |= b_perm;
+       *a_perm = perm;
+       return !perm;
 }
 
 /**
- * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
+ * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
  *
  * @type:      Type of operation.
  * @filename:  Filename.
+ * @mode:      Create mode.
+ * @major:     Device major number.
+ * @minor:     Device minor number.
  * @domain:    Pointer to "struct tomoyo_domain_info".
  * @is_delete: True if it is a delete request.
  *
@@ -825,71 +672,58 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_path_acl(const u8 type, const char *filename,
-                                 struct tomoyo_domain_info *const domain,
-                                 const bool is_delete)
+static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
+                                         char *mode, char *major, char *minor,
+                                         struct tomoyo_domain_info * const
+                                         domain, const bool is_delete)
 {
-       static const u32 tomoyo_rw_mask =
-               (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
-       const u32 perm = 1 << type;
-       struct tomoyo_acl_info *ptr;
-       struct tomoyo_path_acl e = {
-               .head.type = TOMOYO_TYPE_PATH_ACL,
-               .perm_high = perm >> 16,
-               .perm = perm
+       struct tomoyo_mkdev_acl e = {
+               .head.type = TOMOYO_TYPE_MKDEV_ACL,
+               .perm = 1 << type
        };
        int error = is_delete ? -ENOENT : -ENOMEM;
-
-       if (type == TOMOYO_TYPE_READ_WRITE)
-               e.perm |= tomoyo_rw_mask;
-       if (!domain)
-               return -EINVAL;
-       if (!tomoyo_parse_name_union(filename, &e.name))
-               return -EINVAL;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
+       if (!tomoyo_parse_name_union(filename, &e.name) ||
+           !tomoyo_parse_number_union(mode, &e.mode) ||
+           !tomoyo_parse_number_union(major, &e.major) ||
+           !tomoyo_parse_number_union(minor, &e.minor))
                goto out;
-       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-               struct tomoyo_path_acl *acl =
-                       container_of(ptr, struct tomoyo_path_acl, head);
-               if (!tomoyo_is_same_path_acl(acl, &e))
-                       continue;
-               if (is_delete) {
-                       if (perm <= 0xFFFF)
-                               acl->perm &= ~perm;
-                       else
-                               acl->perm_high &= ~(perm >> 16);
-                       if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
-                               acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
-                       else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-                               acl->perm &= ~tomoyo_rw_mask;
-               } else {
-                       if (perm <= 0xFFFF)
-                               acl->perm |= perm;
-                       else
-                               acl->perm_high |= (perm >> 16);
-                       if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
-                               acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
-                       else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
-                               acl->perm |= tomoyo_rw_mask;
-               }
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_path_acl *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->head.list,
-                                         &domain->acl_info_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
+       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+                                    tomoyo_same_mkdev_acl,
+                                    tomoyo_merge_mkdev_acl);
  out:
        tomoyo_put_name_union(&e.name);
+       tomoyo_put_number_union(&e.mode);
+       tomoyo_put_number_union(&e.major);
+       tomoyo_put_number_union(&e.minor);
        return error;
 }
 
+static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
+                                 const struct tomoyo_acl_info *b)
+{
+       const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
+       const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
+       return tomoyo_same_acl_head(&p1->head, &p2->head)
+               && tomoyo_same_name_union(&p1->name1, &p2->name1)
+               && tomoyo_same_name_union(&p1->name2, &p2->name2);
+}
+
+static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
+                                  struct tomoyo_acl_info *b,
+                                  const bool is_delete)
+{
+       u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
+               ->perm;
+       u8 perm = *a_perm;
+       const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
+       if (is_delete)
+               perm &= ~b_perm;
+       else
+               perm |= b_perm;
+       *a_perm = perm;
+       return !perm;
+}
+
 /**
  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
  *
@@ -905,46 +739,20 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
  */
 static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
                                   const char *filename2,
-                                  struct tomoyo_domain_info *const domain,
+                                  struct tomoyo_domain_info * const domain,
                                   const bool is_delete)
 {
-       const u8 perm = 1 << type;
        struct tomoyo_path2_acl e = {
                .head.type = TOMOYO_TYPE_PATH2_ACL,
-               .perm = perm
+               .perm = 1 << type
        };
-       struct tomoyo_acl_info *ptr;
        int error = is_delete ? -ENOENT : -ENOMEM;
-
-       if (!domain)
-               return -EINVAL;
        if (!tomoyo_parse_name_union(filename1, &e.name1) ||
            !tomoyo_parse_name_union(filename2, &e.name2))
                goto out;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-               struct tomoyo_path2_acl *acl =
-                       container_of(ptr, struct tomoyo_path2_acl, head);
-               if (!tomoyo_is_same_path2_acl(acl, &e))
-                       continue;
-               if (is_delete)
-                       acl->perm &= ~perm;
-               else
-                       acl->perm |= perm;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_path2_acl *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->head.list,
-                                         &domain->acl_info_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
+       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+                                    tomoyo_same_path2_acl,
+                                    tomoyo_merge_path2_acl);
  out:
        tomoyo_put_name_union(&e.name1);
        tomoyo_put_name_union(&e.name2);
@@ -952,134 +760,158 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
 }
 
 /**
- * tomoyo_path_acl - Check permission for single path operation.
- *
- * @domain:   Pointer to "struct tomoyo_domain_info".
- * @type:     Type of operation.
- * @filename: Filename to check.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
-                          const struct tomoyo_path_info *filename)
-{
-       if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
-               return 0;
-       return tomoyo_path_acl2(domain, filename, 1 << type, 1);
-}
-
-/**
- * tomoyo_path2_acl - Check permission for double path operation.
+ * tomoyo_path_permission - Check permission for single path operation.
  *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @type:      Type of operation.
- * @filename1: First filename to check.
- * @filename2: Second filename to check.
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
-                           const u8 type,
-                           const struct tomoyo_path_info *filename1,
-                           const struct tomoyo_path_info *filename2)
-{
-       struct tomoyo_acl_info *ptr;
-       const u8 perm = 1 << type;
-       int error = -EPERM;
-
-       if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
-               return 0;
-       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-               struct tomoyo_path2_acl *acl;
-               if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
-                       continue;
-               acl = container_of(ptr, struct tomoyo_path2_acl, head);
-               if (!(acl->perm & perm))
-                       continue;
-               if (!tomoyo_compare_name_union(filename1, &acl->name1))
-                       continue;
-               if (!tomoyo_compare_name_union(filename2, &acl->name2))
-                       continue;
-               error = 0;
-               break;
-       }
-       return error;
-}
-
-/**
- * tomoyo_path_permission2 - Check permission for single path operation.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @r:         Pointer to "struct tomoyo_request_info".
  * @operation: Type of operation.
  * @filename:  Filename to check.
- * @mode:      Access control mode.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
-                                  u8 operation,
-                                  const struct tomoyo_path_info *filename,
-                                  const u8 mode)
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+                          const struct tomoyo_path_info *filename)
 {
-       const char *msg;
        int error;
-       const bool is_enforce = (mode == 3);
 
-       if (!mode)
-               return 0;
  next:
-       error = tomoyo_path_acl(domain, operation, filename);
-       msg = tomoyo_path2keyword(operation);
-       if (!error)
-               goto ok;
-       if (tomoyo_verbose_mode(domain))
-               printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
-                      tomoyo_get_msg(is_enforce), msg, filename->name,
-                      tomoyo_get_last_name(domain));
-       if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-               const char *name = tomoyo_get_file_pattern(filename)->name;
-               tomoyo_update_path_acl(operation, name, domain, false);
-       }
-       if (!is_enforce)
-               error = 0;
- ok:
+       r->type = tomoyo_p2mac[operation];
+       r->mode = tomoyo_get_mode(r->profile, r->type);
+       if (r->mode == TOMOYO_CONFIG_DISABLED)
+               return 0;
+       r->param_type = TOMOYO_TYPE_PATH_ACL;
+       r->param.path.filename = filename;
+       r->param.path.operation = operation;
+       do {
+               tomoyo_check_acl(r, tomoyo_check_path_acl);
+               if (!r->granted && operation == TOMOYO_TYPE_READ &&
+                   !r->domain->ignore_global_allow_read &&
+                   tomoyo_globally_readable_file(filename))
+                       r->granted = true;
+               error = tomoyo_audit_path_log(r);
+               /*
+                * Do not retry for execute request, for alias may have
+                * changed.
+                */
+       } while (error == TOMOYO_RETRY_REQUEST &&
+                operation != TOMOYO_TYPE_EXECUTE);
        /*
         * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
         * we need to check "allow_rewrite" permission if the filename is
         * specified by "deny_rewrite" keyword.
         */
        if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
-           tomoyo_is_no_rewrite_file(filename)) {
+           tomoyo_no_rewrite_file(filename)) {
                operation = TOMOYO_TYPE_REWRITE;
                goto next;
        }
        return error;
 }
 
+static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
+                                       const struct tomoyo_acl_info *b)
+{
+       const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
+                                                              head);
+       const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
+                                                              head);
+       return tomoyo_same_acl_head(&p1->head, &p2->head)
+               && tomoyo_same_name_union(&p1->name, &p2->name)
+               && tomoyo_same_number_union(&p1->number, &p2->number);
+}
+
+static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
+                                        struct tomoyo_acl_info *b,
+                                        const bool is_delete)
+{
+       u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
+                                         head)->perm;
+       u8 perm = *a_perm;
+       const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
+               ->perm;
+       if (is_delete)
+               perm &= ~b_perm;
+       else
+               perm |= b_perm;
+       *a_perm = perm;
+       return !perm;
+}
+
 /**
- * tomoyo_check_exec_perm - Check permission for "execute".
+ * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
+ *
+ * @type:      Type of operation.
+ * @filename:  Filename.
+ * @number:    Number.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
  *
- * @domain:   Pointer to "struct tomoyo_domain_info".
- * @filename: Check permission for "execute".
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
+                                        char *number,
+                                        struct tomoyo_domain_info * const
+                                        domain,
+                                        const bool is_delete)
+{
+       struct tomoyo_path_number_acl e = {
+               .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
+               .perm = 1 << type
+       };
+       int error = is_delete ? -ENOENT : -ENOMEM;
+       if (!tomoyo_parse_name_union(filename, &e.name))
+               return -EINVAL;
+       if (!tomoyo_parse_number_union(number, &e.number))
+               goto out;
+       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+                                    tomoyo_same_path_number_acl,
+                                    tomoyo_merge_path_number_acl);
+ out:
+       tomoyo_put_name_union(&e.name);
+       tomoyo_put_number_union(&e.number);
+       return error;
+}
+
+/**
+ * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
  *
- * Returns 0 on success, negativevalue otherwise.
+ * @type:   Type of operation.
+ * @path:   Pointer to "struct path".
+ * @number: Number.
  *
- * Caller holds tomoyo_read_lock().
+ * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
-                          const struct tomoyo_path_info *filename)
+int tomoyo_path_number_perm(const u8 type, struct path *path,
+                           unsigned long number)
 {
-       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+       struct tomoyo_request_info r;
+       int error = -ENOMEM;
+       struct tomoyo_path_info buf;
+       int idx;
 
-       if (!mode)
+       if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
+           == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
                return 0;
-       return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
+       idx = tomoyo_read_lock();
+       if (!tomoyo_get_realpath(&buf, path))
+               goto out;
+       if (type == TOMOYO_TYPE_MKDIR)
+               tomoyo_add_slash(&buf);
+       r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
+       r.param.path_number.operation = type;
+       r.param.path_number.filename = &buf;
+       r.param.path_number.number = number;
+       do {
+               tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
+               error = tomoyo_audit_path_number_log(&r);
+       } while (error == TOMOYO_RETRY_REQUEST);
+       kfree(buf.name);
+ out:
+       tomoyo_read_unlock(idx);
+       if (r.mode != TOMOYO_CONFIG_ENFORCING)
+               error = 0;
+       return error;
 }
 
 /**
@@ -1096,24 +928,17 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 {
        const u8 acc_mode = ACC_MODE(flag);
        int error = -ENOMEM;
-       struct tomoyo_path_info *buf;
-       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-       const bool is_enforce = (mode == 3);
+       struct tomoyo_path_info buf;
+       struct tomoyo_request_info r;
        int idx;
 
-       if (!mode || !path->mnt)
-               return 0;
-       if (acc_mode == 0)
-               return 0;
-       if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
-               /*
-                * I don't check directories here because mkdir() and rmdir()
-                * don't call me.
-                */
+       if (!path->mnt ||
+           (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
                return 0;
+       buf.name = NULL;
+       r.mode = TOMOYO_CONFIG_DISABLED;
        idx = tomoyo_read_lock();
-       buf = tomoyo_get_path(path);
-       if (!buf)
+       if (!tomoyo_get_realpath(&buf, path))
                goto out;
        error = 0;
        /*
@@ -1121,28 +946,43 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
         * we need to check "allow_rewrite" permission when the filename is not
         * opened for append mode or the filename is truncated at open time.
         */
-       if ((acc_mode & MAY_WRITE) &&
-           ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
-           (tomoyo_is_no_rewrite_file(buf))) {
-               error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE,
-                                               buf, mode);
+       if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
+           && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+           != TOMOYO_CONFIG_DISABLED) {
+               if (!tomoyo_get_realpath(&buf, path)) {
+                       error = -ENOMEM;
+                       goto out;
+               }
+               if (tomoyo_no_rewrite_file(&buf))
+                       error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
+                                                      &buf);
+       }
+       if (!error && acc_mode &&
+           tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
+           != TOMOYO_CONFIG_DISABLED) {
+               u8 operation;
+               if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
+                       error = -ENOMEM;
+                       goto out;
+               }
+               if (acc_mode == (MAY_READ | MAY_WRITE))
+                       operation = TOMOYO_TYPE_READ_WRITE;
+               else if (acc_mode == MAY_READ)
+                       operation = TOMOYO_TYPE_READ;
+               else
+                       operation = TOMOYO_TYPE_WRITE;
+               error = tomoyo_path_permission(&r, operation, &buf);
        }
-       if (!error)
-               error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
-                                               mode);
-       if (!error && (flag & O_TRUNC))
-               error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE,
-                                               buf, mode);
  out:
-       kfree(buf);
+       kfree(buf.name);
        tomoyo_read_unlock(idx);
-       if (!is_enforce)
+       if (r.mode != TOMOYO_CONFIG_ENFORCING)
                error = 0;
        return error;
 }
 
 /**
- * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
  *
  * @operation: Type of operation.
  * @path:      Pointer to "struct path".
@@ -1152,71 +992,79 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 int tomoyo_path_perm(const u8 operation, struct path *path)
 {
        int error = -ENOMEM;
-       struct tomoyo_path_info *buf;
-       struct tomoyo_domain_info *domain = tomoyo_domain();
-       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-       const bool is_enforce = (mode == 3);
+       struct tomoyo_path_info buf;
+       struct tomoyo_request_info r;
        int idx;
 
-       if (!mode || !path->mnt)
+       if (!path->mnt)
                return 0;
+       if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
+           == TOMOYO_CONFIG_DISABLED)
+               return 0;
+       buf.name = NULL;
        idx = tomoyo_read_lock();
-       buf = tomoyo_get_path(path);
-       if (!buf)
+       if (!tomoyo_get_realpath(&buf, path))
                goto out;
        switch (operation) {
-       case TOMOYO_TYPE_MKDIR:
+       case TOMOYO_TYPE_REWRITE:
+               if (!tomoyo_no_rewrite_file(&buf)) {
+                       error = 0;
+                       goto out;
+               }
+               break;
        case TOMOYO_TYPE_RMDIR:
        case TOMOYO_TYPE_CHROOT:
-               if (!buf->is_dir) {
-                       /*
-                        * tomoyo_get_path() reserves space for appending "/."
-                        */
-                       strcat((char *) buf->name, "/");
-                       tomoyo_fill_path_info(buf);
-               }
+       case TOMOYO_TYPE_UMOUNT:
+               tomoyo_add_slash(&buf);
+               break;
        }
-       error = tomoyo_path_permission2(domain, operation, buf, mode);
+       error = tomoyo_path_permission(&r, operation, &buf);
  out:
-       kfree(buf);
+       kfree(buf.name);
        tomoyo_read_unlock(idx);
-       if (!is_enforce)
+       if (r.mode != TOMOYO_CONFIG_ENFORCING)
                error = 0;
        return error;
 }
 
 /**
- * tomoyo_check_rewrite_permission - Check permission for "rewrite".
+ * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
  *
- * @filp: Pointer to "struct file".
+ * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
+ * @path:      Pointer to "struct path".
+ * @mode:      Create mode.
+ * @dev:       Device number.
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_check_rewrite_permission(struct file *filp)
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+                            const unsigned int mode, unsigned int dev)
 {
+       struct tomoyo_request_info r;
        int error = -ENOMEM;
-       struct tomoyo_domain_info *domain = tomoyo_domain();
-       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-       const bool is_enforce = (mode == 3);
-       struct tomoyo_path_info *buf;
+       struct tomoyo_path_info buf;
        int idx;
 
-       if (!mode || !filp->f_path.mnt)
+       if (!path->mnt ||
+           tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+           == TOMOYO_CONFIG_DISABLED)
                return 0;
-
        idx = tomoyo_read_lock();
-       buf = tomoyo_get_path(&filp->f_path);
-       if (!buf)
-               goto out;
-       if (!tomoyo_is_no_rewrite_file(buf)) {
-               error = 0;
-               goto out;
+       error = -ENOMEM;
+       if (tomoyo_get_realpath(&buf, path)) {
+               dev = new_decode_dev(dev);
+               r.param_type = TOMOYO_TYPE_MKDEV_ACL;
+               r.param.mkdev.filename = &buf;
+               r.param.mkdev.operation = operation;
+               r.param.mkdev.mode = mode;
+               r.param.mkdev.major = MAJOR(dev);
+               r.param.mkdev.minor = MINOR(dev);
+               tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
+               error = tomoyo_audit_mkdev_log(&r);
+               kfree(buf.name);
        }
-       error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode);
- out:
-       kfree(buf);
        tomoyo_read_unlock(idx);
-       if (!is_enforce)
+       if (r.mode != TOMOYO_CONFIG_ENFORCING)
                error = 0;
        return error;
 }
@@ -1234,56 +1082,99 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
                      struct path *path2)
 {
        int error = -ENOMEM;
-       struct tomoyo_path_info *buf1, *buf2;
-       struct tomoyo_domain_info *domain = tomoyo_domain();
-       const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-       const bool is_enforce = (mode == 3);
-       const char *msg;
+       struct tomoyo_path_info buf1;
+       struct tomoyo_path_info buf2;
+       struct tomoyo_request_info r;
        int idx;
 
-       if (!mode || !path1->mnt || !path2->mnt)
+       if (!path1->mnt || !path2->mnt ||
+           tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+           == TOMOYO_CONFIG_DISABLED)
                return 0;
+       buf1.name = NULL;
+       buf2.name = NULL;
        idx = tomoyo_read_lock();
-       buf1 = tomoyo_get_path(path1);
-       buf2 = tomoyo_get_path(path2);
-       if (!buf1 || !buf2)
-               goto out;
-       {
-               struct dentry *dentry = path1->dentry;
-               if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
-                       /*
-                        * tomoyo_get_path() reserves space for appending "/."
-                        */
-                       if (!buf1->is_dir) {
-                               strcat((char *) buf1->name, "/");
-                               tomoyo_fill_path_info(buf1);
-                       }
-                       if (!buf2->is_dir) {
-                               strcat((char *) buf2->name, "/");
-                               tomoyo_fill_path_info(buf2);
-                       }
-               }
-       }
-       error = tomoyo_path2_acl(domain, operation, buf1, buf2);
-       msg = tomoyo_path22keyword(operation);
-       if (!error)
+       if (!tomoyo_get_realpath(&buf1, path1) ||
+           !tomoyo_get_realpath(&buf2, path2))
                goto out;
-       if (tomoyo_verbose_mode(domain))
-               printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
-                      "denied for %s\n", tomoyo_get_msg(is_enforce),
-                      msg, buf1->name, buf2->name,
-                      tomoyo_get_last_name(domain));
-       if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-               const char *name1 = tomoyo_get_file_pattern(buf1)->name;
-               const char *name2 = tomoyo_get_file_pattern(buf2)->name;
-               tomoyo_update_path2_acl(operation, name1, name2, domain,
-                                       false);
-       }
+       switch (operation) {
+               struct dentry *dentry;
+       case TOMOYO_TYPE_RENAME:
+        case TOMOYO_TYPE_LINK:
+               dentry = path1->dentry;
+               if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+                        break;
+                /* fall through */
+        case TOMOYO_TYPE_PIVOT_ROOT:
+                tomoyo_add_slash(&buf1);
+                tomoyo_add_slash(&buf2);
+               break;
+        }
+       r.param_type = TOMOYO_TYPE_PATH2_ACL;
+       r.param.path2.operation = operation;
+       r.param.path2.filename1 = &buf1;
+       r.param.path2.filename2 = &buf2;
+       do {
+               tomoyo_check_acl(&r, tomoyo_check_path2_acl);
+               error = tomoyo_audit_path2_log(&r);
+       } while (error == TOMOYO_RETRY_REQUEST);
  out:
-       kfree(buf1);
-       kfree(buf2);
+       kfree(buf1.name);
+       kfree(buf2.name);
        tomoyo_read_unlock(idx);
-       if (!is_enforce)
+       if (r.mode != TOMOYO_CONFIG_ENFORCING)
                error = 0;
        return error;
 }
+
+/**
+ * tomoyo_write_file - Update file related list.
+ *
+ * @data:      String to parse.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
+                     const bool is_delete)
+{
+       char *w[5];
+       u8 type;
+       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+               return -EINVAL;
+       if (strncmp(w[0], "allow_", 6))
+               goto out;
+       w[0] += 6;
+       for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
+               if (strcmp(w[0], tomoyo_path_keyword[type]))
+                       continue;
+               return tomoyo_update_path_acl(type, w[1], domain, is_delete);
+       }
+       if (!w[2][0])
+               goto out;
+       for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
+               if (strcmp(w[0], tomoyo_path2_keyword[type]))
+                       continue;
+               return tomoyo_update_path2_acl(type, w[1], w[2], domain,
+                                              is_delete);
+       }
+       for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
+               if (strcmp(w[0], tomoyo_path_number_keyword[type]))
+                       continue;
+               return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
+                                                    is_delete);
+       }
+       if (!w[3][0] || !w[4][0])
+               goto out;
+       for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
+               if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
+                       continue;
+               return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
+                                              w[4], domain, is_delete);
+       }
+ out:
+       return -EINVAL;
+}
index b9cc71b04314b0b50b8f301cacb9b9ac432ad963..a877e4c3b1019d962da68ad792816d8e6aa28e1d 100644 (file)
 #include <linux/kthread.h>
 #include <linux/slab.h>
 
-enum tomoyo_gc_id {
-       TOMOYO_ID_PATH_GROUP,
-       TOMOYO_ID_PATH_GROUP_MEMBER,
-       TOMOYO_ID_DOMAIN_INITIALIZER,
-       TOMOYO_ID_DOMAIN_KEEPER,
-       TOMOYO_ID_ALIAS,
-       TOMOYO_ID_GLOBALLY_READABLE,
-       TOMOYO_ID_PATTERN,
-       TOMOYO_ID_NO_REWRITE,
-       TOMOYO_ID_MANAGER,
-       TOMOYO_ID_NAME,
-       TOMOYO_ID_ACL,
-       TOMOYO_ID_DOMAIN
-};
-
-struct tomoyo_gc_entry {
+struct tomoyo_gc {
        struct list_head list;
        int type;
-       void *element;
+       struct list_head *element;
 };
 static LIST_HEAD(tomoyo_gc_queue);
 static DEFINE_MUTEX(tomoyo_gc_mutex);
 
 /* Caller holds tomoyo_policy_lock mutex. */
-static bool tomoyo_add_to_gc(const int type, void *element)
+static bool tomoyo_add_to_gc(const int type, struct list_head *element)
 {
-       struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry)
                return false;
        entry->type = type;
        entry->element = element;
        list_add(&entry->list, &tomoyo_gc_queue);
+       list_del_rcu(element);
        return true;
 }
 
-static void tomoyo_del_allow_read
-(struct tomoyo_globally_readable_file_entry *ptr)
+static void tomoyo_del_allow_read(struct list_head *element)
 {
+       struct tomoyo_readable_file *ptr =
+               container_of(element, typeof(*ptr), head.list);
        tomoyo_put_name(ptr->filename);
 }
 
-static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
+static void tomoyo_del_file_pattern(struct list_head *element)
 {
+       struct tomoyo_no_pattern *ptr =
+               container_of(element, typeof(*ptr), head.list);
        tomoyo_put_name(ptr->pattern);
 }
 
-static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
+static void tomoyo_del_no_rewrite(struct list_head *element)
 {
+       struct tomoyo_no_rewrite *ptr =
+               container_of(element, typeof(*ptr), head.list);
        tomoyo_put_name(ptr->pattern);
 }
 
-static void tomoyo_del_domain_initializer
-(struct tomoyo_domain_initializer_entry *ptr)
+static void tomoyo_del_transition_control(struct list_head *element)
 {
+       struct tomoyo_transition_control *ptr =
+               container_of(element, typeof(*ptr), head.list);
        tomoyo_put_name(ptr->domainname);
        tomoyo_put_name(ptr->program);
 }
 
-static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
-{
-       tomoyo_put_name(ptr->domainname);
-       tomoyo_put_name(ptr->program);
-}
-
-static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
+static void tomoyo_del_aggregator(struct list_head *element)
 {
+       struct tomoyo_aggregator *ptr =
+               container_of(element, typeof(*ptr), head.list);
        tomoyo_put_name(ptr->original_name);
-       tomoyo_put_name(ptr->aliased_name);
+       tomoyo_put_name(ptr->aggregated_name);
 }
 
-static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
+static void tomoyo_del_manager(struct list_head *element)
 {
+       struct tomoyo_manager *ptr =
+               container_of(element, typeof(*ptr), head.list);
        tomoyo_put_name(ptr->manager);
 }
 
-static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
+static void tomoyo_del_acl(struct list_head *element)
 {
+       struct tomoyo_acl_info *acl =
+               container_of(element, typeof(*acl), list);
        switch (acl->type) {
        case TOMOYO_TYPE_PATH_ACL:
                {
@@ -104,14 +96,41 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
                        tomoyo_put_name_union(&entry->name2);
                }
                break;
-       default:
-               printk(KERN_WARNING "Unknown type\n");
+       case TOMOYO_TYPE_PATH_NUMBER_ACL:
+               {
+                       struct tomoyo_path_number_acl *entry
+                               = container_of(acl, typeof(*entry), head);
+                       tomoyo_put_name_union(&entry->name);
+                       tomoyo_put_number_union(&entry->number);
+               }
+               break;
+       case TOMOYO_TYPE_MKDEV_ACL:
+               {
+                       struct tomoyo_mkdev_acl *entry
+                               = container_of(acl, typeof(*entry), head);
+                       tomoyo_put_name_union(&entry->name);
+                       tomoyo_put_number_union(&entry->mode);
+                       tomoyo_put_number_union(&entry->major);
+                       tomoyo_put_number_union(&entry->minor);
+               }
+               break;
+       case TOMOYO_TYPE_MOUNT_ACL:
+               {
+                       struct tomoyo_mount_acl *entry
+                               = container_of(acl, typeof(*entry), head);
+                       tomoyo_put_name_union(&entry->dev_name);
+                       tomoyo_put_name_union(&entry->dir_name);
+                       tomoyo_put_name_union(&entry->fs_type);
+                       tomoyo_put_number_union(&entry->flags);
+               }
                break;
        }
 }
 
-static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
+static bool tomoyo_del_domain(struct list_head *element)
 {
+       struct tomoyo_domain_info *domain =
+               container_of(element, typeof(*domain), list);
        struct tomoyo_acl_info *acl;
        struct tomoyo_acl_info *tmp;
        /*
@@ -139,7 +158,7 @@ static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
        if (atomic_read(&domain->users))
                return false;
        list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
-               tomoyo_del_acl(acl);
+               tomoyo_del_acl(&acl->list);
                tomoyo_memory_free(acl);
        }
        tomoyo_put_name(domain->domainname);
@@ -147,135 +166,70 @@ static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
 }
 
 
-static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
+static void tomoyo_del_name(struct list_head *element)
 {
+       const struct tomoyo_name *ptr =
+               container_of(element, typeof(*ptr), list);
 }
 
-static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
-                                        *member)
+static void tomoyo_del_path_group(struct list_head *element)
 {
+       struct tomoyo_path_group *member =
+               container_of(element, typeof(*member), head.list);
        tomoyo_put_name(member->member_name);
 }
 
-static void tomoyo_del_path_group(struct tomoyo_path_group *group)
+static void tomoyo_del_group(struct list_head *element)
 {
+       struct tomoyo_group *group =
+               container_of(element, typeof(*group), list);
        tomoyo_put_name(group->group_name);
 }
 
+static void tomoyo_del_number_group(struct list_head *element)
+{
+       struct tomoyo_number_group *member =
+               container_of(element, typeof(*member), head.list);
+}
+
+static bool tomoyo_collect_member(struct list_head *member_list, int id)
+{
+       struct tomoyo_acl_head *member;
+       list_for_each_entry(member, member_list, list) {
+               if (!member->is_deleted)
+                       continue;
+               if (!tomoyo_add_to_gc(id, &member->list))
+                       return false;
+       }
+        return true;
+}
+
+static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
+{
+       struct tomoyo_acl_info *acl;
+       list_for_each_entry(acl, &domain->acl_info_list, list) {
+               if (!acl->is_deleted)
+                       continue;
+               if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
+                       return false;
+       }
+       return true;
+}
+
 static void tomoyo_collect_entry(void)
 {
+       int i;
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return;
-       {
-               struct tomoyo_globally_readable_file_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
-                                       list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
-       }
-       {
-               struct tomoyo_pattern_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
-       }
-       {
-               struct tomoyo_no_rewrite_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
-       }
-       {
-               struct tomoyo_domain_initializer_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
-                                       list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
-       }
-       {
-               struct tomoyo_domain_keeper_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
-       }
-       {
-               struct tomoyo_alias_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
-       }
-       {
-               struct tomoyo_policy_manager_entry *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
-                                       list) {
-                       if (!ptr->is_deleted)
-                               continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
-                               list_del_rcu(&ptr->list);
-                       else
-                               break;
-               }
+       for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
+               if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
+                       goto unlock;
        }
        {
                struct tomoyo_domain_info *domain;
                list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-                       struct tomoyo_acl_info *acl;
-                       list_for_each_entry_rcu(acl, &domain->acl_info_list,
-                                               list) {
-                               switch (acl->type) {
-                               case TOMOYO_TYPE_PATH_ACL:
-                                       if (container_of(acl,
-                                        struct tomoyo_path_acl,
-                                                        head)->perm ||
-                                           container_of(acl,
-                                        struct tomoyo_path_acl,
-                                                        head)->perm_high)
-                                               continue;
-                                       break;
-                               case TOMOYO_TYPE_PATH2_ACL:
-                                       if (container_of(acl,
-                                        struct tomoyo_path2_acl,
-                                                        head)->perm)
-                                               continue;
-                                       break;
-                               default:
-                                       continue;
-                               }
-                               if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
-                                       list_del_rcu(&acl->list);
-                               else
-                                       break;
-                       }
+                       if (!tomoyo_collect_acl(domain))
+                               goto unlock;
                        if (!domain->is_deleted || atomic_read(&domain->users))
                                continue;
                        /*
@@ -283,104 +237,92 @@ static void tomoyo_collect_entry(void)
                         * refer this domain after successful execve().
                         * We recheck domain->users after SRCU synchronization.
                         */
-                       if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
-                               list_del_rcu(&domain->list);
-                       else
-                               break;
+                       if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
+                               goto unlock;
                }
        }
-       {
-               int i;
-               for (i = 0; i < TOMOYO_MAX_HASH; i++) {
-                       struct tomoyo_name_entry *ptr;
-                       list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
-                                               list) {
-                               if (atomic_read(&ptr->users))
-                                       continue;
-                               if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
-                                       list_del_rcu(&ptr->list);
-                               else {
-                                       i = TOMOYO_MAX_HASH;
-                                       break;
-                               }
-                       }
+       for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+               struct tomoyo_name *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
+                       if (atomic_read(&ptr->users))
+                               continue;
+                       if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
+                               goto unlock;
                }
        }
-       {
-               struct tomoyo_path_group *group;
-               list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
-                       struct tomoyo_path_group_member *member;
-                       list_for_each_entry_rcu(member, &group->member_list,
-                                               list) {
-                               if (!member->is_deleted)
-                                       continue;
-                               if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
-                                                    member))
-                                       list_del_rcu(&member->list);
-                               else
-                                       break;
-                       }
+       for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
+               struct list_head *list = &tomoyo_group_list[i];
+               int id;
+               struct tomoyo_group *group;
+               switch (i) {
+               case 0:
+                       id = TOMOYO_ID_PATH_GROUP;
+                       break;
+               default:
+                       id = TOMOYO_ID_NUMBER_GROUP;
+                       break;
+               }
+               list_for_each_entry(group, list, list) {
+                       if (!tomoyo_collect_member(&group->member_list, id))
+                               goto unlock;
                        if (!list_empty(&group->member_list) ||
                            atomic_read(&group->users))
                                continue;
-                       if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
-                               list_del_rcu(&group->list);
-                       else
-                               break;
+                       if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
+                               goto unlock;
                }
        }
+ unlock:
        mutex_unlock(&tomoyo_policy_lock);
 }
 
 static void tomoyo_kfree_entry(void)
 {
-       struct tomoyo_gc_entry *p;
-       struct tomoyo_gc_entry *tmp;
+       struct tomoyo_gc *p;
+       struct tomoyo_gc *tmp;
 
        list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
+               struct list_head *element = p->element;
                switch (p->type) {
-               case TOMOYO_ID_DOMAIN_INITIALIZER:
-                       tomoyo_del_domain_initializer(p->element);
-                       break;
-               case TOMOYO_ID_DOMAIN_KEEPER:
-                       tomoyo_del_domain_keeper(p->element);
+               case TOMOYO_ID_TRANSITION_CONTROL:
+                       tomoyo_del_transition_control(element);
                        break;
-               case TOMOYO_ID_ALIAS:
-                       tomoyo_del_alias(p->element);
+               case TOMOYO_ID_AGGREGATOR:
+                       tomoyo_del_aggregator(element);
                        break;
                case TOMOYO_ID_GLOBALLY_READABLE:
-                       tomoyo_del_allow_read(p->element);
+                       tomoyo_del_allow_read(element);
                        break;
                case TOMOYO_ID_PATTERN:
-                       tomoyo_del_file_pattern(p->element);
+                       tomoyo_del_file_pattern(element);
                        break;
                case TOMOYO_ID_NO_REWRITE:
-                       tomoyo_del_no_rewrite(p->element);
+                       tomoyo_del_no_rewrite(element);
                        break;
                case TOMOYO_ID_MANAGER:
-                       tomoyo_del_manager(p->element);
+                       tomoyo_del_manager(element);
                        break;
                case TOMOYO_ID_NAME:
-                       tomoyo_del_name(p->element);
+                       tomoyo_del_name(element);
                        break;
                case TOMOYO_ID_ACL:
-                       tomoyo_del_acl(p->element);
+                       tomoyo_del_acl(element);
                        break;
                case TOMOYO_ID_DOMAIN:
-                       if (!tomoyo_del_domain(p->element))
+                       if (!tomoyo_del_domain(element))
                                continue;
                        break;
-               case TOMOYO_ID_PATH_GROUP_MEMBER:
-                       tomoyo_del_path_group_member(p->element);
-                       break;
                case TOMOYO_ID_PATH_GROUP:
-                       tomoyo_del_path_group(p->element);
+                       tomoyo_del_path_group(element);
                        break;
-               default:
-                       printk(KERN_WARNING "Unknown type\n");
+               case TOMOYO_ID_GROUP:
+                       tomoyo_del_group(element);
+                       break;
+               case TOMOYO_ID_NUMBER_GROUP:
+                       tomoyo_del_number_group(element);
                        break;
                }
-               tomoyo_memory_free(p->element);
+               tomoyo_memory_free(element);
                list_del(&p->list);
                kfree(p);
        }
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c
new file mode 100644 (file)
index 0000000..e94352c
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * security/tomoyo/group.c
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a,
+                               const struct tomoyo_acl_head *b)
+{
+       return container_of(a, struct tomoyo_path_group, head)->member_name ==
+               container_of(b, struct tomoyo_path_group, head)->member_name;
+}
+
+static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
+                                 const struct tomoyo_acl_head *b)
+{
+       return !memcmp(&container_of(a, struct tomoyo_number_group, head)
+                      ->number,
+                      &container_of(b, struct tomoyo_number_group, head)
+                      ->number,
+                      sizeof(container_of(a, struct tomoyo_number_group, head)
+                             ->number));
+}
+
+/**
+ * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
+ *
+ * @data:      String to parse.
+ * @is_delete: True if it is a delete request.
+ * @type:      Type of this group.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_group(char *data, const bool is_delete, const u8 type)
+{
+       struct tomoyo_group *group;
+       struct list_head *member;
+       char *w[2];
+       int error = -EINVAL;
+       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+               return -EINVAL;
+       group = tomoyo_get_group(w[0], type);
+       if (!group)
+               return -ENOMEM;
+       member = &group->member_list;
+       if (type == TOMOYO_PATH_GROUP) {
+               struct tomoyo_path_group e = { };
+               e.member_name = tomoyo_get_name(w[1]);
+               if (!e.member_name) {
+                       error = -ENOMEM;
+                       goto out;
+               }
+               error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                            member, tomoyo_same_path_group);
+               tomoyo_put_name(e.member_name);
+       } else if (type == TOMOYO_NUMBER_GROUP) {
+               struct tomoyo_number_group e = { };
+               if (w[1][0] == '@'
+                   || !tomoyo_parse_number_union(w[1], &e.number)
+                   || e.number.values[0] > e.number.values[1])
+                       goto out;
+               error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+                                            member, tomoyo_same_number_group);
+               /*
+                * tomoyo_put_number_union() is not needed because
+                * w[1][0] != '@'.
+                */
+       }
+ out:
+       tomoyo_put_group(group);
+       return error;
+}
+
+/**
+ * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
+ *
+ * @pathname:        The name of pathname.
+ * @group:           Pointer to "struct tomoyo_path_group".
+ *
+ * Returns matched member's pathname if @pathname matches pathnames in @group,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+                         const struct tomoyo_group *group)
+{
+       struct tomoyo_path_group *member;
+       list_for_each_entry_rcu(member, &group->member_list, head.list) {
+               if (member->head.is_deleted)
+                       continue;
+               if (!tomoyo_path_matches_pattern(pathname, member->member_name))
+                       continue;
+               return member->member_name;
+       }
+       return NULL;
+}
+
+/**
+ * tomoyo_number_matches_group - Check whether the given number matches members of the given number group.
+ *
+ * @min:   Min number.
+ * @max:   Max number.
+ * @group: Pointer to "struct tomoyo_number_group".
+ *
+ * Returns true if @min and @max partially overlaps @group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_number_matches_group(const unsigned long min,
+                                const unsigned long max,
+                                const struct tomoyo_group *group)
+{
+       struct tomoyo_number_group *member;
+       bool matched = false;
+       list_for_each_entry_rcu(member, &group->member_list, head.list) {
+               if (member->head.is_deleted)
+                       continue;
+               if (min > member->number.values[1] ||
+                   max < member->number.values[0])
+                       continue;
+               matched = true;
+               break;
+       }
+       return matched;
+}
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
new file mode 100644 (file)
index 0000000..bbada7c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * security/tomoyo/load_policy.c
+ *
+ * Policy loader launcher for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+/* path to policy loader */
+static const char *tomoyo_loader = "/sbin/tomoyo-init";
+
+/**
+ * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ *
+ * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ */
+static bool tomoyo_policy_loader_exists(void)
+{
+       /*
+        * Don't activate MAC if the policy loader doesn't exist.
+        * If the initrd includes /sbin/init but real-root-dev has not
+        * mounted on / yet, activating MAC will block the system since
+        * policies are not loaded yet.
+        * Thus, let do_execve() call this function everytime.
+        */
+       struct path path;
+
+       if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
+               printk(KERN_INFO "Not activating Mandatory Access Control now "
+                      "since %s doesn't exist.\n", tomoyo_loader);
+               return false;
+       }
+       path_put(&path);
+       return true;
+}
+
+/**
+ * tomoyo_load_policy - Run external policy loader to load policy.
+ *
+ * @filename: The program about to start.
+ *
+ * This function checks whether @filename is /sbin/init , and if so
+ * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
+ * and then continues invocation of /sbin/init.
+ * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
+ * writes to /sys/kernel/security/tomoyo/ interfaces.
+ *
+ * Returns nothing.
+ */
+void tomoyo_load_policy(const char *filename)
+{
+       char *argv[2];
+       char *envp[3];
+
+       if (tomoyo_policy_loaded)
+               return;
+       /*
+        * Check filename is /sbin/init or /sbin/tomoyo-start.
+        * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
+        * be passed.
+        * You can create /sbin/tomoyo-start by
+        * "ln -s /bin/true /sbin/tomoyo-start".
+        */
+       if (strcmp(filename, "/sbin/init") &&
+           strcmp(filename, "/sbin/tomoyo-start"))
+               return;
+       if (!tomoyo_policy_loader_exists())
+               return;
+
+       printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
+              tomoyo_loader);
+       argv[0] = (char *) tomoyo_loader;
+       argv[1] = NULL;
+       envp[0] = "HOME=/";
+       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+       envp[2] = NULL;
+       call_usermodehelper(argv[0], argv, envp, 1);
+       tomoyo_check_profile();
+}
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c
new file mode 100644 (file)
index 0000000..2976126
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * security/tomoyo/memory.c
+ *
+ * Memory management functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/hash.h>
+#include <linux/slab.h>
+#include "common.h"
+
+/**
+ * tomoyo_warn_oom - Print out of memory warning message.
+ *
+ * @function: Function's name.
+ */
+void tomoyo_warn_oom(const char *function)
+{
+       /* Reduce error messages. */
+       static pid_t tomoyo_last_pid;
+       const pid_t pid = current->pid;
+       if (tomoyo_last_pid != pid) {
+               printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
+                      function);
+               tomoyo_last_pid = pid;
+       }
+       if (!tomoyo_policy_loaded)
+               panic("MAC Initialization failed.\n");
+}
+
+/* Memory allocated for policy. */
+static atomic_t tomoyo_policy_memory_size;
+/* Quota for holding policy. */
+static unsigned int tomoyo_quota_for_policy;
+
+/**
+ * tomoyo_memory_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ */
+bool tomoyo_memory_ok(void *ptr)
+{
+       size_t s = ptr ? ksize(ptr) : 0;
+       atomic_add(s, &tomoyo_policy_memory_size);
+       if (ptr && (!tomoyo_quota_for_policy ||
+                   atomic_read(&tomoyo_policy_memory_size)
+                   <= tomoyo_quota_for_policy)) {
+               memset(ptr, 0, s);
+               return true;
+       }
+       atomic_sub(s, &tomoyo_policy_memory_size);
+       tomoyo_warn_oom(__func__);
+       return false;
+}
+
+/**
+ * tomoyo_commit_ok - Check memory quota.
+ *
+ * @data:   Data to copy from.
+ * @size:   Size in byte.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ * @data is zero-cleared on success.
+ */
+void *tomoyo_commit_ok(void *data, const unsigned int size)
+{
+       void *ptr = kzalloc(size, GFP_NOFS);
+       if (tomoyo_memory_ok(ptr)) {
+               memmove(ptr, data, size);
+               memset(data, 0, size);
+               return ptr;
+       }
+       return NULL;
+}
+
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr:  Pointer to allocated memory.
+ */
+void tomoyo_memory_free(void *ptr)
+{
+       atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
+       kfree(ptr);
+}
+
+/**
+ * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ *
+ * @group_name: The name of address group.
+ * @idx:        Index number.
+ *
+ * Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
+ */
+struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
+{
+       struct tomoyo_group e = { };
+       struct tomoyo_group *group = NULL;
+       bool found = false;
+       if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
+               return NULL;
+       e.group_name = tomoyo_get_name(group_name);
+       if (!e.group_name)
+               return NULL;
+       if (mutex_lock_interruptible(&tomoyo_policy_lock))
+               goto out;
+       list_for_each_entry(group, &tomoyo_group_list[idx], list) {
+               if (e.group_name != group->group_name)
+                       continue;
+               atomic_inc(&group->users);
+               found = true;
+               break;
+       }
+       if (!found) {
+               struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
+               if (entry) {
+                       INIT_LIST_HEAD(&entry->member_list);
+                       atomic_set(&entry->users, 1);
+                       list_add_tail_rcu(&entry->list,
+                                         &tomoyo_group_list[idx]);
+                       group = entry;
+                       found = true;
+               }
+       }
+       mutex_unlock(&tomoyo_policy_lock);
+ out:
+       tomoyo_put_name(e.group_name);
+       return found ? group : NULL;
+}
+
+/*
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
+ */
+struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+
+/**
+ * tomoyo_get_name - Allocate permanent memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
+{
+       struct tomoyo_name *ptr;
+       unsigned int hash;
+       int len;
+       int allocated_len;
+       struct list_head *head;
+
+       if (!name)
+               return NULL;
+       len = strlen(name) + 1;
+       hash = full_name_hash((const unsigned char *) name, len - 1);
+       head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
+       if (mutex_lock_interruptible(&tomoyo_policy_lock))
+               return NULL;
+       list_for_each_entry(ptr, head, list) {
+               if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+                       continue;
+               atomic_inc(&ptr->users);
+               goto out;
+       }
+       ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
+       allocated_len = ptr ? ksize(ptr) : 0;
+       if (!ptr || (tomoyo_quota_for_policy &&
+                    atomic_read(&tomoyo_policy_memory_size) + allocated_len
+                    > tomoyo_quota_for_policy)) {
+               kfree(ptr);
+               ptr = NULL;
+               tomoyo_warn_oom(__func__);
+               goto out;
+       }
+       atomic_add(allocated_len, &tomoyo_policy_memory_size);
+       ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+       memmove((char *) ptr->entry.name, name, len);
+       atomic_set(&ptr->users, 1);
+       tomoyo_fill_path_info(&ptr->entry);
+       list_add_tail(&ptr->list, head);
+ out:
+       mutex_unlock(&tomoyo_policy_lock);
+       return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_mm_init - Initialize mm related code.
+ */
+void __init tomoyo_mm_init(void)
+{
+       int idx;
+
+       for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
+               INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
+       for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
+               INIT_LIST_HEAD(&tomoyo_group_list[idx]);
+       for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
+               INIT_LIST_HEAD(&tomoyo_name_list[idx]);
+       INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+       tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
+       list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+       idx = tomoyo_read_lock();
+       if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+               panic("Can't register tomoyo_kernel_domain");
+       {
+               /* Load built-in policy. */
+               tomoyo_write_transition_control("/sbin/hotplug", false,
+                                       TOMOYO_TRANSITION_CONTROL_INITIALIZE);
+               tomoyo_write_transition_control("/sbin/modprobe", false,
+                                       TOMOYO_TRANSITION_CONTROL_INITIALIZE);
+       }
+       tomoyo_read_unlock(idx);
+}
+
+
+/* Memory allocated for query lists. */
+unsigned int tomoyo_query_memory_size;
+/* Quota for holding query lists. */
+unsigned int tomoyo_quota_for_query;
+
+/**
+ * tomoyo_read_memory_counter - Check for memory usage in bytes.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns memory usage.
+ */
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
+{
+       if (!head->r.eof) {
+               const unsigned int policy
+                       = atomic_read(&tomoyo_policy_memory_size);
+               const unsigned int query = tomoyo_query_memory_size;
+               char buffer[64];
+
+               memset(buffer, 0, sizeof(buffer));
+               if (tomoyo_quota_for_policy)
+                       snprintf(buffer, sizeof(buffer) - 1,
+                                "   (Quota: %10u)",
+                                tomoyo_quota_for_policy);
+               else
+                       buffer[0] = '\0';
+               tomoyo_io_printf(head, "Policy:       %10u%s\n", policy,
+                                buffer);
+               if (tomoyo_quota_for_query)
+                       snprintf(buffer, sizeof(buffer) - 1,
+                                "   (Quota: %10u)",
+                                tomoyo_quota_for_query);
+               else
+                       buffer[0] = '\0';
+               tomoyo_io_printf(head, "Query lists:  %10u%s\n", query,
+                                buffer);
+               tomoyo_io_printf(head, "Total:        %10u\n", policy + query);
+               head->r.eof = true;
+       }
+}
+
+/**
+ * tomoyo_write_memory_quota - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       unsigned int size;
+
+       if (sscanf(data, "Policy: %u", &size) == 1)
+               tomoyo_quota_for_policy = size;
+       else if (sscanf(data, "Query lists: %u", &size) == 1)
+               tomoyo_quota_for_query = size;
+       return 0;
+}
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
new file mode 100644 (file)
index 0000000..82bf8c2
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Keywords for mount restrictions. */
+
+/* Allow to call 'mount --bind /source_dir /dest_dir' */
+#define TOMOYO_MOUNT_BIND_KEYWORD                        "--bind"
+/* Allow to call 'mount --move /old_dir    /new_dir ' */
+#define TOMOYO_MOUNT_MOVE_KEYWORD                        "--move"
+/* Allow to call 'mount -o remount /dir             ' */
+#define TOMOYO_MOUNT_REMOUNT_KEYWORD                     "--remount"
+/* Allow to call 'mount --make-unbindable /dir'       */
+#define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD             "--make-unbindable"
+/* Allow to call 'mount --make-private /dir'          */
+#define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD                "--make-private"
+/* Allow to call 'mount --make-slave /dir'            */
+#define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD                  "--make-slave"
+/* Allow to call 'mount --make-shared /dir'           */
+#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD                 "--make-shared"
+
+/**
+ * tomoyo_audit_mount_log - Audit mount log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
+{
+       const char *dev = r->param.mount.dev->name;
+       const char *dir = r->param.mount.dir->name;
+       const char *type = r->param.mount.type->name;
+       const unsigned long flags = r->param.mount.flags;
+       if (r->granted)
+               return 0;
+       if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
+               tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
+       else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
+                || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
+               tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
+                               flags);
+       else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+                !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+                !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+                !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
+               tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
+       else
+               tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
+                               flags);
+       return tomoyo_supervisor(r,
+                                TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
+                                tomoyo_pattern(r->param.mount.dev),
+                                tomoyo_pattern(r->param.mount.dir), type,
+                                flags);
+}
+
+static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
+                                  const struct tomoyo_acl_info *ptr)
+{
+       const struct tomoyo_mount_acl *acl =
+               container_of(ptr, typeof(*acl), head);
+       return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
+               tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
+               tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
+               (!r->param.mount.need_dev ||
+                tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
+}
+
+/**
+ * tomoyo_mount_acl - Check permission for mount() operation.
+ *
+ * @r:        Pointer to "struct tomoyo_request_info".
+ * @dev_name: Name of device file.
+ * @dir:      Pointer to "struct path".
+ * @type:     Name of filesystem type.
+ * @flags:    Mount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
+                           struct path *dir, char *type, unsigned long flags)
+{
+       struct path path;
+       struct file_system_type *fstype = NULL;
+       const char *requested_type = NULL;
+       const char *requested_dir_name = NULL;
+       const char *requested_dev_name = NULL;
+       struct tomoyo_path_info rtype;
+       struct tomoyo_path_info rdev;
+       struct tomoyo_path_info rdir;
+       int need_dev = 0;
+       int error = -ENOMEM;
+
+       /* Get fstype. */
+       requested_type = tomoyo_encode(type);
+       if (!requested_type)
+               goto out;
+       rtype.name = requested_type;
+       tomoyo_fill_path_info(&rtype);
+
+       /* Get mount point. */
+       requested_dir_name = tomoyo_realpath_from_path(dir);
+       if (!requested_dir_name) {
+               error = -ENOMEM;
+               goto out;
+       }
+       rdir.name = requested_dir_name;
+       tomoyo_fill_path_info(&rdir);
+
+       /* Compare fs name. */
+       if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) {
+               /* dev_name is ignored. */
+       } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+                  !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+                  !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+                  !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) {
+               /* dev_name is ignored. */
+       } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) ||
+                  !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) {
+               need_dev = -1; /* dev_name is a directory */
+       } else {
+               fstype = get_fs_type(type);
+               if (!fstype) {
+                       error = -ENODEV;
+                       goto out;
+               }
+               if (fstype->fs_flags & FS_REQUIRES_DEV)
+                       /* dev_name is a block device file. */
+                       need_dev = 1;
+       }
+       if (need_dev) {
+               /* Get mount point or device file. */
+               if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
+                       error = -ENOENT;
+                       goto out;
+               }
+               requested_dev_name = tomoyo_realpath_from_path(&path);
+               if (!requested_dev_name) {
+                       error = -ENOENT;
+                       goto out;
+               }
+       } else {
+               /* Map dev_name to "<NULL>" if no dev_name given. */
+               if (!dev_name)
+                       dev_name = "<NULL>";
+               requested_dev_name = tomoyo_encode(dev_name);
+               if (!requested_dev_name) {
+                       error = -ENOMEM;
+                       goto out;
+               }
+       }
+       rdev.name = requested_dev_name;
+       tomoyo_fill_path_info(&rdev);
+       r->param_type = TOMOYO_TYPE_MOUNT_ACL;
+       r->param.mount.need_dev = need_dev;
+       r->param.mount.dev = &rdev;
+       r->param.mount.dir = &rdir;
+       r->param.mount.type = &rtype;
+       r->param.mount.flags = flags;
+       do {
+               tomoyo_check_acl(r, tomoyo_check_mount_acl);
+               error = tomoyo_audit_mount_log(r);
+       } while (error == TOMOYO_RETRY_REQUEST);
+ out:
+       kfree(requested_dev_name);
+       kfree(requested_dir_name);
+       if (fstype)
+               put_filesystem(fstype);
+       kfree(requested_type);
+       return error;
+}
+
+/**
+ * tomoyo_mount_permission - Check permission for mount() operation.
+ *
+ * @dev_name:  Name of device file.
+ * @path:      Pointer to "struct path".
+ * @type:      Name of filesystem type. May be NULL.
+ * @flags:     Mount options.
+ * @data_page: Optional data. May be NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+                           unsigned long flags, void *data_page)
+{
+       struct tomoyo_request_info r;
+       int error;
+       int idx;
+
+       if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+           == TOMOYO_CONFIG_DISABLED)
+               return 0;
+       if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+               flags &= ~MS_MGC_MSK;
+       if (flags & MS_REMOUNT) {
+               type = TOMOYO_MOUNT_REMOUNT_KEYWORD;
+               flags &= ~MS_REMOUNT;
+       }
+       if (flags & MS_MOVE) {
+               type = TOMOYO_MOUNT_MOVE_KEYWORD;
+               flags &= ~MS_MOVE;
+       }
+       if (flags & MS_BIND) {
+               type = TOMOYO_MOUNT_BIND_KEYWORD;
+               flags &= ~MS_BIND;
+       }
+       if (flags & MS_UNBINDABLE) {
+               type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD;
+               flags &= ~MS_UNBINDABLE;
+       }
+       if (flags & MS_PRIVATE) {
+               type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD;
+               flags &= ~MS_PRIVATE;
+       }
+       if (flags & MS_SLAVE) {
+               type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD;
+               flags &= ~MS_SLAVE;
+       }
+       if (flags & MS_SHARED) {
+               type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD;
+               flags &= ~MS_SHARED;
+       }
+       if (!type)
+               type = "<NULL>";
+       idx = tomoyo_read_lock();
+       error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
+       tomoyo_read_unlock(idx);
+       return error;
+}
+
+static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
+                                 const struct tomoyo_acl_info *b)
+{
+       const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
+       const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+       return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+               tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
+               tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
+               tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
+               tomoyo_same_number_union(&p1->flags, &p2->flags);
+}
+
+/**
+ * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list.
+ *
+ * @data:      String to parse.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
+                      const bool is_delete)
+{
+       struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+       int error = is_delete ? -ENOENT : -ENOMEM;
+       char *w[4];
+       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
+               return -EINVAL;
+       if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
+           !tomoyo_parse_name_union(w[1], &e.dir_name) ||
+           !tomoyo_parse_name_union(w[2], &e.fs_type) ||
+           !tomoyo_parse_number_union(w[3], &e.flags))
+               goto out;
+       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+                                    tomoyo_same_mount_acl, NULL);
+ out:
+       tomoyo_put_name_union(&e.dev_name);
+       tomoyo_put_name_union(&e.dir_name);
+       tomoyo_put_name_union(&e.fs_type);
+       tomoyo_put_number_union(&e.flags);
+       return error;
+}
diff --git a/security/tomoyo/path_group.c b/security/tomoyo/path_group.c
deleted file mode 100644 (file)
index c988041..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * security/tomoyo/path_group.c
- *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- */
-
-#include <linux/slab.h>
-#include "common.h"
-/* The list for "struct ccs_path_group". */
-LIST_HEAD(tomoyo_path_group_list);
-
-/**
- * tomoyo_get_path_group - Allocate memory for "struct tomoyo_path_group".
- *
- * @group_name: The name of pathname group.
- *
- * Returns pointer to "struct tomoyo_path_group" on success, NULL otherwise.
- */
-struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name)
-{
-       struct tomoyo_path_group *entry = NULL;
-       struct tomoyo_path_group *group = NULL;
-       const struct tomoyo_path_info *saved_group_name;
-       int error = -ENOMEM;
-       if (!tomoyo_is_correct_path(group_name, 0, 0, 0) ||
-           !group_name[0])
-               return NULL;
-       saved_group_name = tomoyo_get_name(group_name);
-       if (!saved_group_name)
-               return NULL;
-       entry = kzalloc(sizeof(*entry), GFP_NOFS);
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
-               if (saved_group_name != group->group_name)
-                       continue;
-               atomic_inc(&group->users);
-               error = 0;
-               break;
-       }
-       if (error && tomoyo_memory_ok(entry)) {
-               INIT_LIST_HEAD(&entry->member_list);
-               entry->group_name = saved_group_name;
-               saved_group_name = NULL;
-               atomic_set(&entry->users, 1);
-               list_add_tail_rcu(&entry->list, &tomoyo_path_group_list);
-               group = entry;
-               entry = NULL;
-               error = 0;
-       }
-       mutex_unlock(&tomoyo_policy_lock);
- out:
-       tomoyo_put_name(saved_group_name);
-       kfree(entry);
-       return !error ? group : NULL;
-}
-
-/**
- * tomoyo_write_path_group_policy - Write "struct tomoyo_path_group" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, nagative value otherwise.
- */
-int tomoyo_write_path_group_policy(char *data, const bool is_delete)
-{
-       struct tomoyo_path_group *group;
-       struct tomoyo_path_group_member *member;
-       struct tomoyo_path_group_member e = { };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-       char *w[2];
-       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
-               return -EINVAL;
-       group = tomoyo_get_path_group(w[0]);
-       if (!group)
-               return -ENOMEM;
-       e.member_name = tomoyo_get_name(w[1]);
-       if (!e.member_name)
-               goto out;
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               goto out;
-       list_for_each_entry_rcu(member, &group->member_list, list) {
-               if (member->member_name != e.member_name)
-                       continue;
-               member->is_deleted = is_delete;
-               error = 0;
-               break;
-       }
-       if (!is_delete && error) {
-               struct tomoyo_path_group_member *entry =
-                       tomoyo_commit_ok(&e, sizeof(e));
-               if (entry) {
-                       list_add_tail_rcu(&entry->list, &group->member_list);
-                       error = 0;
-               }
-       }
-       mutex_unlock(&tomoyo_policy_lock);
- out:
-       tomoyo_put_name(e.member_name);
-       tomoyo_put_path_group(group);
-       return error;
-}
-
-/**
- * tomoyo_read_path_group_policy - Read "struct tomoyo_path_group" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head)
-{
-       struct list_head *gpos;
-       struct list_head *mpos;
-       list_for_each_cookie(gpos, head->read_var1, &tomoyo_path_group_list) {
-               struct tomoyo_path_group *group;
-               group = list_entry(gpos, struct tomoyo_path_group, list);
-               list_for_each_cookie(mpos, head->read_var2,
-                                    &group->member_list) {
-                       struct tomoyo_path_group_member *member;
-                       member = list_entry(mpos,
-                                           struct tomoyo_path_group_member,
-                                           list);
-                       if (member->is_deleted)
-                               continue;
-                       if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_PATH_GROUP
-                                             "%s %s\n",
-                                             group->group_name->name,
-                                             member->member_name->name))
-                               return false;
-               }
-       }
-       return true;
-}
-
-/**
- * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
- *
- * @pathname:        The name of pathname.
- * @group:           Pointer to "struct tomoyo_path_group".
- * @may_use_pattern: True if wild card is permitted.
- *
- * Returns true if @pathname matches pathnames in @group, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-                              const struct tomoyo_path_group *group,
-                              const bool may_use_pattern)
-{
-       struct tomoyo_path_group_member *member;
-       bool matched = false;
-       list_for_each_entry_rcu(member, &group->member_list, list) {
-               if (member->is_deleted)
-                       continue;
-               if (!member->member_name->is_patterned) {
-                       if (tomoyo_pathcmp(pathname, member->member_name))
-                               continue;
-               } else if (may_use_pattern) {
-                       if (!tomoyo_path_matches_pattern(pathname,
-                                                        member->member_name))
-                               continue;
-               } else
-                       continue;
-               matched = true;
-               break;
-       }
-       return matched;
-}
index d1b96f0196216cb23f9da450ac75413b6ffd69c6..ed8ccd680102b53d98f9b98cb9a3aa05c8143090 100644 (file)
 /*
  * security/tomoyo/realpath.c
  *
- * Get the canonicalized absolute pathnames. The basis for TOMOYO.
- *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
+ * Pathname calculation functions for TOMOYO.
  *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include <linux/types.h>
 #include <linux/mount.h>
 #include <linux/mnt_namespace.h>
 #include <linux/fs_struct.h>
-#include <linux/hash.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <net/sock.h>
 #include "common.h"
 
 /**
  * tomoyo_encode: Convert binary string to ascii string.
  *
- * @buffer:  Buffer for ASCII string.
- * @buflen:  Size of @buffer.
- * @str:     Binary string.
+ * @str: String in binary format.
+ *
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
  *
- * Returns 0 on success, -ENOMEM otherwise.
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
  */
-int tomoyo_encode(char *buffer, int buflen, const char *str)
+char *tomoyo_encode(const char *str)
 {
-       while (1) {
-               const unsigned char c = *(unsigned char *) str++;
+       int len = 0;
+       const char *p = str;
+       char *cp;
+       char *cp0;
 
-               if (tomoyo_is_valid(c)) {
-                       if (--buflen <= 0)
-                               break;
-                       *buffer++ = (char) c;
-                       if (c != '\\')
-                               continue;
-                       if (--buflen <= 0)
-                               break;
-                       *buffer++ = (char) c;
-                       continue;
-               }
-               if (!c) {
-                       if (--buflen <= 0)
-                               break;
-                       *buffer = '\0';
-                       return 0;
+       if (!p)
+               return NULL;
+       while (*p) {
+               const unsigned char c = *p++;
+               if (c == '\\')
+                       len += 2;
+               else if (c > ' ' && c < 127)
+                       len++;
+               else
+                       len += 4;
+       }
+       len++;
+       /* Reserve space for appending "/". */
+       cp = kzalloc(len + 10, GFP_NOFS);
+       if (!cp)
+               return NULL;
+       cp0 = cp;
+       p = str;
+       while (*p) {
+               const unsigned char c = *p++;
+
+               if (c == '\\') {
+                       *cp++ = '\\';
+                       *cp++ = '\\';
+               } else if (c > ' ' && c < 127) {
+                       *cp++ = c;
+               } else {
+                       *cp++ = '\\';
+                       *cp++ = (c >> 6) + '0';
+                       *cp++ = ((c >> 3) & 7) + '0';
+                       *cp++ = (c & 7) + '0';
                }
-               buflen -= 4;
-               if (buflen <= 0)
-                       break;
-               *buffer++ = '\\';
-               *buffer++ = (c >> 6) + '0';
-               *buffer++ = ((c >> 3) & 7) + '0';
-               *buffer++ = (c & 7) + '0';
        }
-       return -ENOMEM;
+       return cp0;
 }
 
 /**
- * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
+ * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
  *
- * @path:        Pointer to "struct path".
- * @newname:     Pointer to buffer to return value in.
- * @newname_len: Size of @newname.
+ * @path: Pointer to "struct path".
  *
- * Returns 0 on success, negative value otherwise.
+ * Returns the realpath of the given @path on success, NULL otherwise.
  *
  * If dentry is a directory, trailing '/' is appended.
  * Characters out of 0x20 < c < 0x7F range are converted to
  * \ooo style octal string.
  * Character \ is converted to \\ string.
+ *
+ * These functions use kzalloc(), so the caller must call kfree()
+ * if these functions didn't return NULL.
  */
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
-                              int newname_len)
+char *tomoyo_realpath_from_path(struct path *path)
 {
-       int error = -ENOMEM;
+       char *buf = NULL;
+       char *name = NULL;
+       unsigned int buf_len = PAGE_SIZE / 2;
        struct dentry *dentry = path->dentry;
-       char *sp;
-
-       if (!dentry || !path->mnt || !newname || newname_len <= 2048)
-               return -EINVAL;
-       if (dentry->d_op && dentry->d_op->d_dname) {
+       bool is_dir;
+       if (!dentry)
+               return NULL;
+       is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
+       while (1) {
+               struct path ns_root = { .mnt = NULL, .dentry = NULL };
+               char *pos;
+               buf_len <<= 1;
+               kfree(buf);
+               buf = kmalloc(buf_len, GFP_NOFS);
+               if (!buf)
+                       break;
+               /* Get better name for socket. */
+               if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
+                       struct inode *inode = dentry->d_inode;
+                       struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+                       struct sock *sk = sock ? sock->sk : NULL;
+                       if (sk) {
+                               snprintf(buf, buf_len - 1, "socket:[family=%u:"
+                                        "type=%u:protocol=%u]", sk->sk_family,
+                                        sk->sk_type, sk->sk_protocol);
+                       } else {
+                               snprintf(buf, buf_len - 1, "socket:[unknown]");
+                       }
+                       name = tomoyo_encode(buf);
+                       break;
+               }
                /* For "socket:[\$]" and "pipe:[\$]". */
-               static const int offset = 1536;
-               sp = dentry->d_op->d_dname(dentry, newname + offset,
-                                          newname_len - offset);
-       } else {
-               struct path ns_root = {.mnt = NULL, .dentry = NULL};
-
+               if (dentry->d_op && dentry->d_op->d_dname) {
+                       pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
+                       if (IS_ERR(pos))
+                               continue;
+                       name = tomoyo_encode(pos);
+                       break;
+               }
+               /* If we don't have a vfsmount, we can't calculate. */
+               if (!path->mnt)
+                       break;
                spin_lock(&dcache_lock);
                /* go to whatever namespace root we are under */
-               sp = __d_path(path, &ns_root, newname, newname_len);
+               pos = __d_path(path, &ns_root, buf, buf_len);
                spin_unlock(&dcache_lock);
                /* Prepend "/proc" prefix if using internal proc vfs mount. */
-               if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
+               if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
                    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
-                       sp -= 5;
-                       if (sp >= newname)
-                               memcpy(sp, "/proc", 5);
+                       pos -= 5;
+                       if (pos >= buf)
+                               memcpy(pos, "/proc", 5);
                        else
-                               sp = ERR_PTR(-ENOMEM);
-               }
-       }
-       if (IS_ERR(sp))
-               error = PTR_ERR(sp);
-       else
-               error = tomoyo_encode(newname, sp - newname, sp);
-       /* Append trailing '/' if dentry is a directory. */
-       if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
-           && *newname) {
-               sp = newname + strlen(newname);
-               if (*(sp - 1) != '/') {
-                       if (sp < newname + newname_len - 4) {
-                               *sp++ = '/';
-                               *sp = '\0';
-                       } else {
-                               error = -ENOMEM;
-                       }
+                               pos = ERR_PTR(-ENOMEM);
                }
+               if (IS_ERR(pos))
+                       continue;
+               name = tomoyo_encode(pos);
+               break;
        }
-       if (error)
-               printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n");
-       return error;
-}
-
-/**
- * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
- *
- * @path: Pointer to "struct path".
- *
- * Returns the realpath of the given @path on success, NULL otherwise.
- *
- * These functions use kzalloc(), so the caller must call kfree()
- * if these functions didn't return NULL.
- */
-char *tomoyo_realpath_from_path(struct path *path)
-{
-       char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS);
-
-       BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
-                    <= TOMOYO_MAX_PATHNAME_LEN - 1);
-       if (!buf)
-               return NULL;
-       if (tomoyo_realpath_from_path2(path, buf,
-                                      TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
-               return buf;
        kfree(buf);
-       return NULL;
-}
-
-/**
- * tomoyo_realpath - Get realpath of a pathname.
- *
- * @pathname: The pathname to solve.
- *
- * Returns the realpath of @pathname on success, NULL otherwise.
- */
-char *tomoyo_realpath(const char *pathname)
-{
-       struct path path;
-
-       if (pathname && kern_path(pathname, LOOKUP_FOLLOW, &path) == 0) {
-               char *buf = tomoyo_realpath_from_path(&path);
-               path_put(&path);
-               return buf;
+       if (!name)
+               tomoyo_warn_oom(__func__);
+       else if (is_dir && *name) {
+               /* Append trailing '/' if dentry is a directory. */
+               char *pos = name + strlen(name) - 1;
+               if (*pos != '/')
+                       /*
+                        * This is OK because tomoyo_encode() reserves space
+                        * for appending "/".
+                        */
+                       *++pos = '/';
        }
-       return NULL;
+       return name;
 }
 
 /**
@@ -189,191 +179,3 @@ char *tomoyo_realpath_nofollow(const char *pathname)
        }
        return NULL;
 }
-
-/* Memory allocated for non-string data. */
-static atomic_t tomoyo_policy_memory_size;
-/* Quota for holding policy. */
-static unsigned int tomoyo_quota_for_policy;
-
-/**
- * tomoyo_memory_ok - Check memory quota.
- *
- * @ptr: Pointer to allocated memory.
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_policy_lock.
- * Memory pointed by @ptr will be zeroed on success.
- */
-bool tomoyo_memory_ok(void *ptr)
-{
-       int allocated_len = ptr ? ksize(ptr) : 0;
-       atomic_add(allocated_len, &tomoyo_policy_memory_size);
-       if (ptr && (!tomoyo_quota_for_policy ||
-                   atomic_read(&tomoyo_policy_memory_size)
-                   <= tomoyo_quota_for_policy)) {
-               memset(ptr, 0, allocated_len);
-               return true;
-       }
-       printk(KERN_WARNING "ERROR: Out of memory "
-              "for tomoyo_alloc_element().\n");
-       if (!tomoyo_policy_loaded)
-               panic("MAC Initialization failed.\n");
-       return false;
-}
-
-/**
- * tomoyo_commit_ok - Check memory quota.
- *
- * @data:   Data to copy from.
- * @size:   Size in byte.
- *
- * Returns pointer to allocated memory on success, NULL otherwise.
- */
-void *tomoyo_commit_ok(void *data, const unsigned int size)
-{
-       void *ptr = kzalloc(size, GFP_NOFS);
-       if (tomoyo_memory_ok(ptr)) {
-               memmove(ptr, data, size);
-               memset(data, 0, size);
-               return ptr;
-       }
-       return NULL;
-}
-
-/**
- * tomoyo_memory_free - Free memory for elements.
- *
- * @ptr:  Pointer to allocated memory.
- */
-void tomoyo_memory_free(void *ptr)
-{
-       atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
-       kfree(ptr);
-}
-
-/*
- * tomoyo_name_list is used for holding string data used by TOMOYO.
- * Since same string data is likely used for multiple times (e.g.
- * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
- * "const struct tomoyo_path_info *".
- */
-struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
-
-/**
- * tomoyo_get_name - Allocate permanent memory for string data.
- *
- * @name: The string to store into the permernent memory.
- *
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- */
-const struct tomoyo_path_info *tomoyo_get_name(const char *name)
-{
-       struct tomoyo_name_entry *ptr;
-       unsigned int hash;
-       int len;
-       int allocated_len;
-       struct list_head *head;
-
-       if (!name)
-               return NULL;
-       len = strlen(name) + 1;
-       hash = full_name_hash((const unsigned char *) name, len - 1);
-       head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
-       if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               return NULL;
-       list_for_each_entry(ptr, head, list) {
-               if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
-                       continue;
-               atomic_inc(&ptr->users);
-               goto out;
-       }
-       ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
-       allocated_len = ptr ? ksize(ptr) : 0;
-       if (!ptr || (tomoyo_quota_for_policy &&
-                    atomic_read(&tomoyo_policy_memory_size) + allocated_len
-                    > tomoyo_quota_for_policy)) {
-               kfree(ptr);
-               printk(KERN_WARNING "ERROR: Out of memory "
-                      "for tomoyo_get_name().\n");
-               if (!tomoyo_policy_loaded)
-                       panic("MAC Initialization failed.\n");
-               ptr = NULL;
-               goto out;
-       }
-       atomic_add(allocated_len, &tomoyo_policy_memory_size);
-       ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
-       memmove((char *) ptr->entry.name, name, len);
-       atomic_set(&ptr->users, 1);
-       tomoyo_fill_path_info(&ptr->entry);
-       list_add_tail(&ptr->list, head);
- out:
-       mutex_unlock(&tomoyo_policy_lock);
-       return ptr ? &ptr->entry : NULL;
-}
-
-/**
- * tomoyo_realpath_init - Initialize realpath related code.
- */
-void __init tomoyo_realpath_init(void)
-{
-       int i;
-
-       BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
-       for (i = 0; i < TOMOYO_MAX_HASH; i++)
-               INIT_LIST_HEAD(&tomoyo_name_list[i]);
-       INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
-       tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
-       /*
-        * tomoyo_read_lock() is not needed because this function is
-        * called before the first "delete" request.
-        */
-       list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-       if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
-               panic("Can't register tomoyo_kernel_domain");
-}
-
-/**
- * tomoyo_read_memory_counter - Check for memory usage in bytes.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns memory usage.
- */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
-{
-       if (!head->read_eof) {
-               const unsigned int policy
-                       = atomic_read(&tomoyo_policy_memory_size);
-               char buffer[64];
-
-               memset(buffer, 0, sizeof(buffer));
-               if (tomoyo_quota_for_policy)
-                       snprintf(buffer, sizeof(buffer) - 1,
-                                "   (Quota: %10u)",
-                                tomoyo_quota_for_policy);
-               else
-                       buffer[0] = '\0';
-               tomoyo_io_printf(head, "Policy:  %10u%s\n", policy, buffer);
-               tomoyo_io_printf(head, "Total:   %10u\n", policy);
-               head->read_eof = true;
-       }
-       return 0;
-}
-
-/**
- * tomoyo_write_memory_quota - Set memory quota.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
- */
-int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
-{
-       char *data = head->write_buf;
-       unsigned int size;
-
-       if (sscanf(data, "Policy: %u", &size) == 1)
-               tomoyo_quota_for_policy = size;
-       return 0;
-}
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
new file mode 100644 (file)
index 0000000..e43d555
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * security/tomoyo/common.c
+ *
+ * Securityfs interface for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/security.h>
+#include "common.h"
+
+/**
+ * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_open(struct inode *inode, struct file *file)
+{
+       const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
+               - ((u8 *) NULL);
+       return tomoyo_open_control(key, file);
+}
+
+/**
+ * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_release(struct inode *inode, struct file *file)
+{
+       return tomoyo_close_control(file);
+}
+
+/**
+ * tomoyo_poll - poll() for /proc/ccs/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
+{
+       return tomoyo_poll_control(file, wait);
+}
+
+/**
+ * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
+                          loff_t *ppos)
+{
+       return tomoyo_read_control(file, buf, count);
+}
+
+/**
+ * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ */
+static ssize_t tomoyo_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       return tomoyo_write_control(file, buf, count);
+}
+
+/*
+ * tomoyo_operations is a "struct file_operations" which is used for handling
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
+ * See tomoyo_io_buffer for internals.
+ */
+static const struct file_operations tomoyo_operations = {
+       .open    = tomoyo_open,
+       .release = tomoyo_release,
+       .poll    = tomoyo_poll,
+       .read    = tomoyo_read,
+       .write   = tomoyo_write,
+       .llseek  = noop_llseek,
+};
+
+/**
+ * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
+ *
+ * @name:   The name of the interface file.
+ * @mode:   The permission of the interface file.
+ * @parent: The parent directory.
+ * @key:    Type of interface.
+ *
+ * Returns nothing.
+ */
+static void __init tomoyo_create_entry(const char *name, const mode_t mode,
+                                      struct dentry *parent, const u8 key)
+{
+       securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
+                              &tomoyo_operations);
+}
+
+/**
+ * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_initerface_init(void)
+{
+       struct dentry *tomoyo_dir;
+
+       /* Don't create securityfs entries unless registered. */
+       if (current_cred()->security != &tomoyo_kernel_domain)
+               return 0;
+
+       tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
+       tomoyo_create_entry("query",            0600, tomoyo_dir,
+                           TOMOYO_QUERY);
+       tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
+                           TOMOYO_DOMAINPOLICY);
+       tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
+                           TOMOYO_EXCEPTIONPOLICY);
+       tomoyo_create_entry("self_domain",      0400, tomoyo_dir,
+                           TOMOYO_SELFDOMAIN);
+       tomoyo_create_entry(".domain_status",   0600, tomoyo_dir,
+                           TOMOYO_DOMAIN_STATUS);
+       tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
+                           TOMOYO_PROCESS_STATUS);
+       tomoyo_create_entry("meminfo",          0600, tomoyo_dir,
+                           TOMOYO_MEMINFO);
+       tomoyo_create_entry("profile",          0600, tomoyo_dir,
+                           TOMOYO_PROFILE);
+       tomoyo_create_entry("manager",          0600, tomoyo_dir,
+                           TOMOYO_MANAGER);
+       tomoyo_create_entry("version",          0400, tomoyo_dir,
+                           TOMOYO_VERSION);
+       return 0;
+}
+
+fs_initcall(tomoyo_initerface_init);
index dedd97d0c163675a116ec48c95acd119b8547400..95d3f95722378583c4a0bbd1bb97f77d4368d155 100644 (file)
@@ -3,10 +3,7 @@
  *
  * LSM hooks for TOMOYO Linux.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include <linux/security.h>
@@ -96,8 +93,7 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
        return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
 }
 
-static int tomoyo_path_truncate(struct path *path, loff_t length,
-                               unsigned int time_attrs)
+static int tomoyo_path_truncate(struct path *path)
 {
        return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
 }
@@ -112,7 +108,8 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
                             int mode)
 {
        struct path path = { parent->mnt, dentry };
-       return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path);
+       return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
+                                      mode & S_IALLUGO);
 }
 
 static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
@@ -133,6 +130,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
 {
        struct path path = { parent->mnt, dentry };
        int type = TOMOYO_TYPE_CREATE;
+       const unsigned int perm = mode & S_IALLUGO;
 
        switch (mode & S_IFMT) {
        case S_IFCHR:
@@ -141,6 +139,12 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
        case S_IFBLK:
                type = TOMOYO_TYPE_MKBLOCK;
                break;
+       default:
+               goto no_dev;
+       }
+       return tomoyo_mkdev_perm(type, &path, perm, dev);
+ no_dev:
+       switch (mode & S_IFMT) {
        case S_IFIFO:
                type = TOMOYO_TYPE_MKFIFO;
                break;
@@ -148,7 +152,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
                type = TOMOYO_TYPE_MKSOCK;
                break;
        }
-       return tomoyo_path_perm(type, &path);
+       return tomoyo_path_number_perm(type, &path, perm);
 }
 
 static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -173,7 +177,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
                             unsigned long arg)
 {
        if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
-               return tomoyo_check_rewrite_permission(file);
+               return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path);
        return 0;
 }
 
@@ -189,23 +193,24 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
 static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
                             unsigned long arg)
 {
-       return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path);
+       return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd);
 }
 
 static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
                             mode_t mode)
 {
        struct path path = { mnt, dentry };
-       return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path);
+       return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path,
+                                      mode & S_IALLUGO);
 }
 
 static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
 {
        int error = 0;
        if (uid != (uid_t) -1)
-               error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path);
+               error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid);
        if (!error && gid != (gid_t) -1)
-               error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path);
+               error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid);
        return error;
 }
 
@@ -217,7 +222,7 @@ static int tomoyo_path_chroot(struct path *path)
 static int tomoyo_sb_mount(char *dev_name, struct path *path,
                           char *type, unsigned long flags, void *data)
 {
-       return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path);
+       return tomoyo_mount_permission(dev_name, path, type, flags, data);
 }
 
 static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
@@ -277,7 +282,7 @@ static int __init tomoyo_init(void)
                panic("Failure registering TOMOYO Linux");
        printk(KERN_INFO "TOMOYO Linux initialized\n");
        cred->security = &tomoyo_kernel_domain;
-       tomoyo_realpath_init();
+       tomoyo_mm_init();
        return 0;
 }
 
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
new file mode 100644 (file)
index 0000000..9bfc1ee
--- /dev/null
@@ -0,0 +1,963 @@
+/*
+ * security/tomoyo/util.c
+ *
+ * Utility functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Lock for protecting policy. */
+DEFINE_MUTEX(tomoyo_policy_lock);
+
+/* Has /sbin/init started? */
+bool tomoyo_policy_loaded;
+
+/**
+ * tomoyo_parse_ulong - Parse an "unsigned long" value.
+ *
+ * @result: Pointer to "unsigned long".
+ * @str:    Pointer to string to parse.
+ *
+ * Returns value type on success, 0 otherwise.
+ *
+ * The @src is updated to point the first character after the value
+ * on success.
+ */
+static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+{
+       const char *cp = *str;
+       char *ep;
+       int base = 10;
+       if (*cp == '0') {
+               char c = *(cp + 1);
+               if (c == 'x' || c == 'X') {
+                       base = 16;
+                       cp += 2;
+               } else if (c >= '0' && c <= '7') {
+                       base = 8;
+                       cp++;
+               }
+       }
+       *result = simple_strtoul(cp, &ep, base);
+       if (cp == ep)
+               return 0;
+       *str = ep;
+       switch (base) {
+       case 16:
+               return TOMOYO_VALUE_TYPE_HEXADECIMAL;
+       case 8:
+               return TOMOYO_VALUE_TYPE_OCTAL;
+       default:
+               return TOMOYO_VALUE_TYPE_DECIMAL;
+       }
+}
+
+/**
+ * tomoyo_print_ulong - Print an "unsigned long" value.
+ *
+ * @buffer:     Pointer to buffer.
+ * @buffer_len: Size of @buffer.
+ * @value:      An "unsigned long" value.
+ * @type:       Type of @value.
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+                       const unsigned long value, const u8 type)
+{
+       if (type == TOMOYO_VALUE_TYPE_DECIMAL)
+               snprintf(buffer, buffer_len, "%lu", value);
+       else if (type == TOMOYO_VALUE_TYPE_OCTAL)
+               snprintf(buffer, buffer_len, "0%lo", value);
+       else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
+               snprintf(buffer, buffer_len, "0x%lX", value);
+       else
+               snprintf(buffer, buffer_len, "type(%u)", type);
+}
+
+/**
+ * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ *
+ * @filename: Name or name group.
+ * @ptr:      Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_name_union(const char *filename,
+                            struct tomoyo_name_union *ptr)
+{
+       if (!tomoyo_correct_word(filename))
+               return false;
+       if (filename[0] == '@') {
+               ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
+               ptr->is_group = true;
+               return ptr->group != NULL;
+       }
+       ptr->filename = tomoyo_get_name(filename);
+       ptr->is_group = false;
+       return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_number_union - Parse a tomoyo_number_union.
+ *
+ * @data: Number or number range or number group.
+ * @ptr:  Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
+{
+       u8 type;
+       unsigned long v;
+       memset(num, 0, sizeof(*num));
+       if (data[0] == '@') {
+               if (!tomoyo_correct_word(data))
+                       return false;
+               num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
+               num->is_group = true;
+               return num->group != NULL;
+       }
+       type = tomoyo_parse_ulong(&v, &data);
+       if (!type)
+               return false;
+       num->values[0] = v;
+       num->min_type = type;
+       if (!*data) {
+               num->values[1] = v;
+               num->max_type = type;
+               return true;
+       }
+       if (*data++ != '-')
+               return false;
+       type = tomoyo_parse_ulong(&v, &data);
+       if (!type || *data)
+               return false;
+       num->values[1] = v;
+       num->max_type = type;
+       return true;
+}
+
+/**
+ * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
+ *
+ * @str: Pointer to the string.
+ *
+ * Returns true if @str is a \ooo style octal value, false otherwise.
+ *
+ * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
+ * This function verifies that \ooo is in valid range.
+ */
+static inline bool tomoyo_byte_range(const char *str)
+{
+       return *str >= '0' && *str++ <= '3' &&
+               *str >= '0' && *str++ <= '7' &&
+               *str >= '0' && *str <= '7';
+}
+
+/**
+ * tomoyo_alphabet_char - Check whether the character is an alphabet.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an alphabet character, false otherwise.
+ */
+static inline bool tomoyo_alphabet_char(const char c)
+{
+       return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+/**
+ * tomoyo_make_byte - Make byte value from three octal characters.
+ *
+ * @c1: The first character.
+ * @c2: The second character.
+ * @c3: The third character.
+ *
+ * Returns byte value.
+ */
+static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+{
+       return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+}
+
+/**
+ * tomoyo_str_starts - Check whether the given string starts with the given keyword.
+ *
+ * @src:  Pointer to pointer to the string.
+ * @find: Pointer to the keyword.
+ *
+ * Returns true if @src starts with @find, false otherwise.
+ *
+ * The @src is updated to point the first character after the @find
+ * if @src starts with @find.
+ */
+bool tomoyo_str_starts(char **src, const char *find)
+{
+       const int len = strlen(find);
+       char *tmp = *src;
+
+       if (strncmp(tmp, find, len))
+               return false;
+       tmp += len;
+       *src = tmp;
+       return true;
+}
+
+/**
+ * tomoyo_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ *
+ * Returns nothing.
+ */
+void tomoyo_normalize_line(unsigned char *buffer)
+{
+       unsigned char *sp = buffer;
+       unsigned char *dp = buffer;
+       bool first = true;
+
+       while (tomoyo_invalid(*sp))
+               sp++;
+       while (*sp) {
+               if (!first)
+                       *dp++ = ' ';
+               first = false;
+               while (tomoyo_valid(*sp))
+                       *dp++ = *sp++;
+               while (tomoyo_invalid(*sp))
+                       sp++;
+       }
+       *dp = '\0';
+}
+
+/**
+ * tomoyo_tokenize - Tokenize string.
+ *
+ * @buffer: The line to tokenize.
+ * @w:      Pointer to "char *".
+ * @size:   Sizeof @w .
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+{
+       int count = size / sizeof(char *);
+       int i;
+       for (i = 0; i < count; i++)
+               w[i] = "";
+       for (i = 0; i < count; i++) {
+               char *cp = strchr(buffer, ' ');
+               if (cp)
+                       *cp = '\0';
+               w[i] = buffer;
+               if (!cp)
+                       break;
+               buffer = cp + 1;
+       }
+       return i < count || !*buffer;
+}
+
+/**
+ * tomoyo_correct_word2 - Validate a string.
+ *
+ * @string: The string to check. May be non-'\0'-terminated.
+ * @len:    Length of @string.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+static bool tomoyo_correct_word2(const char *string, size_t len)
+{
+       const char *const start = string;
+       bool in_repetition = false;
+       unsigned char c;
+       unsigned char d;
+       unsigned char e;
+       if (!len)
+               goto out;
+       while (len--) {
+               c = *string++;
+               if (c == '\\') {
+                       if (!len--)
+                               goto out;
+                       c = *string++;
+                       switch (c) {
+                       case '\\':  /* "\\" */
+                               continue;
+                       case '$':   /* "\$" */
+                       case '+':   /* "\+" */
+                       case '?':   /* "\?" */
+                       case '*':   /* "\*" */
+                       case '@':   /* "\@" */
+                       case 'x':   /* "\x" */
+                       case 'X':   /* "\X" */
+                       case 'a':   /* "\a" */
+                       case 'A':   /* "\A" */
+                       case '-':   /* "\-" */
+                               continue;
+                       case '{':   /* "/\{" */
+                               if (string - 3 < start || *(string - 3) != '/')
+                                       break;
+                               in_repetition = true;
+                               continue;
+                       case '}':   /* "\}/" */
+                               if (*string != '/')
+                                       break;
+                               if (!in_repetition)
+                                       break;
+                               in_repetition = false;
+                               continue;
+                       case '0':   /* "\ooo" */
+                       case '1':
+                       case '2':
+                       case '3':
+                               if (!len-- || !len--)
+                                       break;
+                               d = *string++;
+                               e = *string++;
+                               if (d < '0' || d > '7' || e < '0' || e > '7')
+                                       break;
+                               c = tomoyo_make_byte(c, d, e);
+                               if (tomoyo_invalid(c))
+                                       continue; /* pattern is not \000 */
+                       }
+                       goto out;
+               } else if (in_repetition && c == '/') {
+                       goto out;
+               } else if (tomoyo_invalid(c)) {
+                       goto out;
+               }
+       }
+       if (in_repetition)
+               goto out;
+       return true;
+ out:
+       return false;
+}
+
+/**
+ * tomoyo_correct_word - Validate a string.
+ *
+ * @string: The string to check.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_word(const char *string)
+{
+       return tomoyo_correct_word2(string, strlen(string));
+}
+
+/**
+ * tomoyo_correct_path - Validate a pathname.
+ *
+ * @filename: The pathname to check.
+ *
+ * Check whether the given pathname follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_path(const char *filename)
+{
+       return *filename == '/' && tomoyo_correct_word(filename);
+}
+
+/**
+ * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_domain(const unsigned char *domainname)
+{
+       if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
+                                  TOMOYO_ROOT_NAME_LEN))
+               goto out;
+       domainname += TOMOYO_ROOT_NAME_LEN;
+       if (!*domainname)
+               return true;
+       if (*domainname++ != ' ')
+               goto out;
+       while (1) {
+               const unsigned char *cp = strchr(domainname, ' ');
+               if (!cp)
+                       break;
+               if (*domainname != '/' ||
+                   !tomoyo_correct_word2(domainname, cp - domainname - 1))
+                       goto out;
+               domainname = cp + 1;
+       }
+       return tomoyo_correct_path(domainname);
+ out:
+       return false;
+}
+
+/**
+ * tomoyo_domain_def - Check whether the given token can be a domainname.
+ *
+ * @buffer: The token to check.
+ *
+ * Returns true if @buffer possibly be a domainname, false otherwise.
+ */
+bool tomoyo_domain_def(const unsigned char *buffer)
+{
+       return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+}
+
+/**
+ * tomoyo_find_domain - Find a domain by the given name.
+ *
+ * @domainname: The domainname to find.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+{
+       struct tomoyo_domain_info *domain;
+       struct tomoyo_path_info name;
+
+       name.name = domainname;
+       tomoyo_fill_path_info(&name);
+       list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+               if (!domain->is_deleted &&
+                   !tomoyo_pathcmp(&name, domain->domainname))
+                       return domain;
+       }
+       return NULL;
+}
+
+/**
+ * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ *
+ * @filename: The string to evaluate.
+ *
+ * Returns the initial length without a pattern in @filename.
+ */
+static int tomoyo_const_part_length(const char *filename)
+{
+       char c;
+       int len = 0;
+
+       if (!filename)
+               return 0;
+       while ((c = *filename++) != '\0') {
+               if (c != '\\') {
+                       len++;
+                       continue;
+               }
+               c = *filename++;
+               switch (c) {
+               case '\\':  /* "\\" */
+                       len += 2;
+                       continue;
+               case '0':   /* "\ooo" */
+               case '1':
+               case '2':
+               case '3':
+                       c = *filename++;
+                       if (c < '0' || c > '7')
+                               break;
+                       c = *filename++;
+                       if (c < '0' || c > '7')
+                               break;
+                       len += 4;
+                       continue;
+               }
+               break;
+       }
+       return len;
+}
+
+/**
+ * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
+ *
+ * The caller sets "struct tomoyo_path_info"->name.
+ */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+{
+       const char *name = ptr->name;
+       const int len = strlen(name);
+
+       ptr->const_len = tomoyo_const_part_length(name);
+       ptr->is_dir = len && (name[len - 1] == '/');
+       ptr->is_patterned = (ptr->const_len < len);
+       ptr->hash = full_name_hash(name, len);
+}
+
+/**
+ * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern2(const char *filename,
+                                        const char *filename_end,
+                                        const char *pattern,
+                                        const char *pattern_end)
+{
+       while (filename < filename_end && pattern < pattern_end) {
+               char c;
+               if (*pattern != '\\') {
+                       if (*filename++ != *pattern++)
+                               return false;
+                       continue;
+               }
+               c = *filename;
+               pattern++;
+               switch (*pattern) {
+                       int i;
+                       int j;
+               case '?':
+                       if (c == '/') {
+                               return false;
+                       } else if (c == '\\') {
+                               if (filename[1] == '\\')
+                                       filename++;
+                               else if (tomoyo_byte_range(filename + 1))
+                                       filename += 3;
+                               else
+                                       return false;
+                       }
+                       break;
+               case '\\':
+                       if (c != '\\')
+                               return false;
+                       if (*++filename != '\\')
+                               return false;
+                       break;
+               case '+':
+                       if (!isdigit(c))
+                               return false;
+                       break;
+               case 'x':
+                       if (!isxdigit(c))
+                               return false;
+                       break;
+               case 'a':
+                       if (!tomoyo_alphabet_char(c))
+                               return false;
+                       break;
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+                       if (c == '\\' && tomoyo_byte_range(filename + 1)
+                           && strncmp(filename + 1, pattern, 3) == 0) {
+                               filename += 3;
+                               pattern += 2;
+                               break;
+                       }
+                       return false; /* Not matched. */
+               case '*':
+               case '@':
+                       for (i = 0; i <= filename_end - filename; i++) {
+                               if (tomoyo_file_matches_pattern2(
+                                                   filename + i, filename_end,
+                                                   pattern + 1, pattern_end))
+                                       return true;
+                               c = filename[i];
+                               if (c == '.' && *pattern == '@')
+                                       break;
+                               if (c != '\\')
+                                       continue;
+                               if (filename[i + 1] == '\\')
+                                       i++;
+                               else if (tomoyo_byte_range(filename + i + 1))
+                                       i += 3;
+                               else
+                                       break; /* Bad pattern. */
+                       }
+                       return false; /* Not matched. */
+               default:
+                       j = 0;
+                       c = *pattern;
+                       if (c == '$') {
+                               while (isdigit(filename[j]))
+                                       j++;
+                       } else if (c == 'X') {
+                               while (isxdigit(filename[j]))
+                                       j++;
+                       } else if (c == 'A') {
+                               while (tomoyo_alphabet_char(filename[j]))
+                                       j++;
+                       }
+                       for (i = 1; i <= j; i++) {
+                               if (tomoyo_file_matches_pattern2(
+                                                   filename + i, filename_end,
+                                                   pattern + 1, pattern_end))
+                                       return true;
+                       }
+                       return false; /* Not matched or bad pattern. */
+               }
+               filename++;
+               pattern++;
+       }
+       while (*pattern == '\\' &&
+              (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
+               pattern += 2;
+       return filename == filename_end && pattern == pattern_end;
+}
+
+/**
+ * tomoyo_file_matches_pattern - Pattern matching without '/' character.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern(const char *filename,
+                                       const char *filename_end,
+                                       const char *pattern,
+                                       const char *pattern_end)
+{
+       const char *pattern_start = pattern;
+       bool first = true;
+       bool result;
+
+       while (pattern < pattern_end - 1) {
+               /* Split at "\-" pattern. */
+               if (*pattern++ != '\\' || *pattern++ != '-')
+                       continue;
+               result = tomoyo_file_matches_pattern2(filename,
+                                                     filename_end,
+                                                     pattern_start,
+                                                     pattern - 2);
+               if (first)
+                       result = !result;
+               if (result)
+                       return false;
+               first = false;
+               pattern_start = pattern;
+       }
+       result = tomoyo_file_matches_pattern2(filename, filename_end,
+                                             pattern_start, pattern_end);
+       return first ? result : !result;
+}
+
+/**
+ * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
+ *
+ * @f: The start of string to check.
+ * @p: The start of pattern to compare.
+ *
+ * Returns true if @f matches @p, false otherwise.
+ */
+static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
+{
+       const char *f_delimiter;
+       const char *p_delimiter;
+
+       while (*f && *p) {
+               f_delimiter = strchr(f, '/');
+               if (!f_delimiter)
+                       f_delimiter = f + strlen(f);
+               p_delimiter = strchr(p, '/');
+               if (!p_delimiter)
+                       p_delimiter = p + strlen(p);
+               if (*p == '\\' && *(p + 1) == '{')
+                       goto recursive;
+               if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
+                                                p_delimiter))
+                       return false;
+               f = f_delimiter;
+               if (*f)
+                       f++;
+               p = p_delimiter;
+               if (*p)
+                       p++;
+       }
+       /* Ignore trailing "\*" and "\@" in @pattern. */
+       while (*p == '\\' &&
+              (*(p + 1) == '*' || *(p + 1) == '@'))
+               p += 2;
+       return !*f && !*p;
+ recursive:
+       /*
+        * The "\{" pattern is permitted only after '/' character.
+        * This guarantees that below "*(p - 1)" is safe.
+        * Also, the "\}" pattern is permitted only before '/' character
+        * so that "\{" + "\}" pair will not break the "\-" operator.
+        */
+       if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
+           *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
+               return false; /* Bad pattern. */
+       do {
+               /* Compare current component with pattern. */
+               if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
+                                                p_delimiter - 2))
+                       break;
+               /* Proceed to next component. */
+               f = f_delimiter;
+               if (!*f)
+                       break;
+               f++;
+               /* Continue comparison. */
+               if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
+                       return true;
+               f_delimiter = strchr(f, '/');
+       } while (f_delimiter);
+       return false; /* Not matched. */
+}
+
+/**
+ * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
+ *
+ * @filename: The filename to check.
+ * @pattern:  The pattern to compare.
+ *
+ * Returns true if matches, false otherwise.
+ *
+ * The following patterns are available.
+ *   \\     \ itself.
+ *   \ooo   Octal representation of a byte.
+ *   \*     Zero or more repetitions of characters other than '/'.
+ *   \@     Zero or more repetitions of characters other than '/' or '.'.
+ *   \?     1 byte character other than '/'.
+ *   \$     One or more repetitions of decimal digits.
+ *   \+     1 decimal digit.
+ *   \X     One or more repetitions of hexadecimal digits.
+ *   \x     1 hexadecimal digit.
+ *   \A     One or more repetitions of alphabet characters.
+ *   \a     1 alphabet character.
+ *
+ *   \-     Subtraction operator.
+ *
+ *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
+ *               /dir/dir/dir/ ).
+ */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+                                const struct tomoyo_path_info *pattern)
+{
+       const char *f = filename->name;
+       const char *p = pattern->name;
+       const int len = pattern->const_len;
+
+       /* If @pattern doesn't contain pattern, I can use strcmp(). */
+       if (!pattern->is_patterned)
+               return !tomoyo_pathcmp(filename, pattern);
+       /* Don't compare directory and non-directory. */
+       if (filename->is_dir != pattern->is_dir)
+               return false;
+       /* Compare the initial length without patterns. */
+       if (strncmp(f, p, len))
+               return false;
+       f += len;
+       p += len;
+       return tomoyo_path_matches_pattern2(f, p);
+}
+
+/**
+ * tomoyo_get_exe - Get tomoyo_realpath() of current process.
+ *
+ * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so the caller must call kfree()
+ * if this function didn't return NULL.
+ */
+const char *tomoyo_get_exe(void)
+{
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       const char *cp = NULL;
+
+       if (!mm)
+               return NULL;
+       down_read(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
+                       cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
+                       break;
+               }
+       }
+       up_read(&mm->mmap_sem);
+       return cp;
+}
+
+/**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @profile: Profile number.
+ * @index:   Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const u8 profile, const u8 index)
+{
+       u8 mode;
+       const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+       if (!tomoyo_policy_loaded)
+               return TOMOYO_CONFIG_DISABLED;
+       mode = tomoyo_profile(profile)->config[index];
+       if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+               mode = tomoyo_profile(profile)->config[category];
+       if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+               mode = tomoyo_profile(profile)->default_config;
+       return mode & 3;
+}
+
+/**
+ * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
+ *
+ * @r:      Pointer to "struct tomoyo_request_info" to initialize.
+ * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index:  Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+                            struct tomoyo_domain_info *domain, const u8 index)
+{
+       u8 profile;
+       memset(r, 0, sizeof(*r));
+       if (!domain)
+               domain = tomoyo_domain();
+       r->domain = domain;
+       profile = domain->profile;
+       r->profile = profile;
+       r->type = index;
+       r->mode = tomoyo_get_mode(profile, index);
+       return r->mode;
+}
+
+/**
+ * tomoyo_last_word - Get last component of a line.
+ *
+ * @line: A line.
+ *
+ * Returns the last word of a line.
+ */
+const char *tomoyo_last_word(const char *name)
+{
+       const char *cp = strrchr(name, ' ');
+       if (cp)
+               return cp + 1;
+       return name;
+}
+
+/**
+ * tomoyo_warn_log - Print warning or error message on console.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+       va_list args;
+       char *buffer;
+       const struct tomoyo_domain_info * const domain = r->domain;
+       const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
+       switch (r->mode) {
+       case TOMOYO_CONFIG_ENFORCING:
+               if (!profile->enforcing->enforcing_verbose)
+                       return;
+               break;
+       case TOMOYO_CONFIG_PERMISSIVE:
+               if (!profile->permissive->permissive_verbose)
+                       return;
+               break;
+       case TOMOYO_CONFIG_LEARNING:
+               if (!profile->learning->learning_verbose)
+                       return;
+               break;
+       }
+       buffer = kmalloc(4096, GFP_NOFS);
+       if (!buffer)
+               return;
+       va_start(args, fmt);
+       vsnprintf(buffer, 4095, fmt, args);
+       va_end(args);
+       buffer[4095] = '\0';
+       printk(KERN_WARNING "%s: Access %s denied for %s\n",
+              r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
+              tomoyo_last_word(domain->domainname->name));
+       kfree(buffer);
+}
+
+/**
+ * tomoyo_domain_quota_is_ok - Check for domain's quota.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
+{
+       unsigned int count = 0;
+       struct tomoyo_domain_info *domain = r->domain;
+       struct tomoyo_acl_info *ptr;
+
+       if (r->mode != TOMOYO_CONFIG_LEARNING)
+               return false;
+       if (!domain)
+               return true;
+       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               if (ptr->is_deleted)
+                       continue;
+               switch (ptr->type) {
+                       u16 perm;
+                       u8 i;
+               case TOMOYO_TYPE_PATH_ACL:
+                       perm = container_of(ptr, struct tomoyo_path_acl, head)
+                               ->perm;
+                       for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
+                               if (perm & (1 << i))
+                                       count++;
+                       if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+                               count -= 2;
+                       break;
+               case TOMOYO_TYPE_PATH2_ACL:
+                       perm = container_of(ptr, struct tomoyo_path2_acl, head)
+                               ->perm;
+                       for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
+                               if (perm & (1 << i))
+                                       count++;
+                       break;
+               case TOMOYO_TYPE_PATH_NUMBER_ACL:
+                       perm = container_of(ptr, struct tomoyo_path_number_acl,
+                                           head)->perm;
+                       for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++)
+                               if (perm & (1 << i))
+                                       count++;
+                       break;
+               case TOMOYO_TYPE_MKDEV_ACL:
+                       perm = container_of(ptr, struct tomoyo_mkdev_acl,
+                                           head)->perm;
+                       for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
+                               if (perm & (1 << i))
+                                       count++;
+                       break;
+               default:
+                       count++;
+               }
+       }
+       if (count < tomoyo_profile(domain->profile)->learning->
+           learning_max_entry)
+               return true;
+       if (!domain->quota_warned) {
+               domain->quota_warned = true;
+               printk(KERN_WARNING "TOMOYO-WARNING: "
+                      "Domain '%s' has so many ACLs to hold. "
+                      "Stopped learning mode.\n", domain->domainname->name);
+       }
+       return false;
+}
index 86067ee786324b294be637b202b5c16e381724d0..2fc53961054ede2dc5cf3b1e62cede04a86c389a 100644 (file)
@@ -52,6 +52,10 @@ struct hdmi_spec {
         */
        struct hda_multi_out multiout;
        unsigned int codec_type;
+
+       /* misc flags */
+       /* PD bit indicates only the update, not the current state */
+       unsigned int old_pin_detect:1;
 };
 
 
@@ -616,6 +620,9 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
  * Unsolicited events
  */
 
+static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
+                              struct hdmi_eld *eld);
+
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -632,6 +639,12 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
        if (index < 0)
                return;
 
+       if (spec->old_pin_detect) {
+               if (pind)
+                       hdmi_present_sense(codec, tag, &spec->sink_eld[index]);
+               pind = spec->sink_eld[index].monitor_present;
+       }
+
        spec->sink_eld[index].monitor_present = pind;
        spec->sink_eld[index].eld_valid = eldv;
 
index 3c10c0b149f4c682d683a6ae21ae837b3fe18f4d..b0652acee9b2725541dc99df2af68513aa84009c 100644 (file)
@@ -478,6 +478,7 @@ static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
 
        codec->spec = spec;
        spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
+       spec->old_pin_detect = 1;
 
        if (hdmi_parse_codec(codec) < 0) {
                codec->spec = NULL;
@@ -508,6 +509,7 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
        spec->multiout.max_channels = 8;
        spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
        spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
+       spec->old_pin_detect = 1;
 
        codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
 
@@ -528,6 +530,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
        spec->multiout.max_channels = 2;
        spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
        spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
+       spec->old_pin_detect = 1;
 
        codec->patch_ops = nvhdmi_patch_ops_2ch;
 
index ff614dd824c1fe97cbfe9ee378b744676bc50e93..596ea2f12cf60a74504efc751a9566265d7b3aeb 100644 (file)
@@ -1267,11 +1267,11 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
        unsigned nid = 0;
        struct alc_spec *spec = codec->spec;
 
+       spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+
        ass = codec->subsystem_id & 0xffff;
-       if (ass != codec->bus->pci->subsystem_device && (ass & 1)) {
-               spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+       if (ass != codec->bus->pci->subsystem_device && (ass & 1))
                goto do_sku;
-       }
 
        nid = 0x1d;
        if (codec->vendor_id == 0x10ec0260)
@@ -5180,8 +5180,24 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #define set_beep_amp(spec, nid, idx, dir) \
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+static struct snd_pci_quirk beep_white_list[] = {
+       SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+       {}
+};
+
+static inline int has_cdefine_beep(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       const struct snd_pci_quirk *q;
+       q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
+       if (q)
+               return q->value;
+       return spec->cdefine.enable_pcbeep;
+}
 #else
 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#define has_cdefine_beep(codec)                0
 #endif
 
 /*
@@ -10566,10 +10582,12 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
+       if (has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
        }
 
        if (board_config != ALC882_AUTO)
@@ -10619,7 +10637,7 @@ static int patch_alc882(struct hda_codec *codec)
 
        set_capture_mixer(codec);
 
-       if (spec->cdefine.enable_pcbeep)
+       if (has_cdefine_beep(codec))
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        if (board_config == ALC882_AUTO)
@@ -12435,7 +12453,7 @@ static int patch_alc262(struct hda_codec *codec)
                }
        }
 
-       if (!spec->no_analog) {
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
                err = snd_hda_attach_beep_device(codec, 0x1);
                if (err < 0) {
                        alc_free(codec);
@@ -12486,7 +12504,7 @@ static int patch_alc262(struct hda_codec *codec)
        }
        if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(codec);
-       if (!spec->no_analog && spec->cdefine.enable_pcbeep)
+       if (!spec->no_analog && has_cdefine_beep(codec))
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
@@ -14458,10 +14476,12 @@ static int patch_alc269(struct hda_codec *codec)
                }
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
+       if (has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
        }
 
        if (board_config != ALC269_AUTO)
@@ -14494,7 +14514,7 @@ static int patch_alc269(struct hda_codec *codec)
 
        if (!spec->cap_mixer)
                set_capture_mixer(codec);
-       if (spec->cdefine.enable_pcbeep)
+       if (has_cdefine_beep(codec))
                set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
        if (board_config == ALC269_AUTO)
@@ -18691,10 +18711,12 @@ static int patch_alc662(struct hda_codec *codec)
                }
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
+       if (has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
        }
 
        if (board_config != ALC662_AUTO)
@@ -18716,7 +18738,7 @@ static int patch_alc662(struct hda_codec *codec)
        if (!spec->cap_mixer)
                set_capture_mixer(codec);
 
-       if (spec->cdefine.enable_pcbeep) {
+       if (has_cdefine_beep(codec)) {
                switch (codec->vendor_id) {
                case 0x10ec0662:
                        set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
new file mode 100644 (file)
index 0000000..15130b5
--- /dev/null
@@ -0,0 +1,4 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+endif
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
new file mode 100644 (file)
index 0000000..fff6450
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Mapping of DWARF debug register numbers into register names.
+ *
+ * Copyright (C) 2010 Will Deacon, ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <libio.h>
+#include <dwarf-regs.h>
+
+struct pt_regs_dwarfnum {
+       const char *name;
+       unsigned int dwarfnum;
+};
+
+#define STR(s) #s
+#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
+#define GPR_DWARFNUM_NAME(num) \
+       {.name = STR(%r##num), .dwarfnum = num}
+#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
+
+/*
+ * Reference:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
+ */
+static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
+       GPR_DWARFNUM_NAME(0),
+       GPR_DWARFNUM_NAME(1),
+       GPR_DWARFNUM_NAME(2),
+       GPR_DWARFNUM_NAME(3),
+       GPR_DWARFNUM_NAME(4),
+       GPR_DWARFNUM_NAME(5),
+       GPR_DWARFNUM_NAME(6),
+       GPR_DWARFNUM_NAME(7),
+       GPR_DWARFNUM_NAME(8),
+       GPR_DWARFNUM_NAME(9),
+       GPR_DWARFNUM_NAME(10),
+       REG_DWARFNUM_NAME("%fp", 11),
+       REG_DWARFNUM_NAME("%ip", 12),
+       REG_DWARFNUM_NAME("%sp", 13),
+       REG_DWARFNUM_NAME("%lr", 14),
+       REG_DWARFNUM_NAME("%pc", 15),
+       REG_DWARFNUM_END,
+};
+
+/**
+ * get_arch_regstr() - lookup register name from it's DWARF register number
+ * @n: the DWARF register number
+ *
+ * get_arch_regstr() returns the name of the register in struct
+ * regdwarfnum_table from it's DWARF register number. If the register is not
+ * found in the table, this returns NULL;
+ */
+const char *get_arch_regstr(unsigned int n)
+{
+       const struct pt_regs_dwarfnum *roff;
+       for (roff = regdwarfnum_table; roff->name != NULL; roff++)
+               if (roff->dwarfnum == n)
+                       return roff->name;
+       return NULL;
+}